1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Don Ahn. 7 * 8 * Copyright (c) 1993, 1994 by 9 * jc@irbs.UUCP (John Capo) 10 * vak@zebub.msk.su (Serge Vakulenko) 11 * ache@astral.msk.su (Andrew A. Chernov) 12 * 13 * Copyright (c) 1993, 1994, 1995 by 14 * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 15 * dufault@hda.com (Peter Dufault) 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 46 * $Id: fd.c,v 1.122 1998/09/15 08:15:28 gibbs Exp $ 47 * 48 */ 49 50 #include "ft.h" 51 #if NFT < 1 52 #undef NFDC 53 #endif 54 #include "fd.h" 55 #include "opt_devfs.h" 56 #include "opt_fdc.h" 57 58 #if NFDC > 0 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/kernel.h> 63 #include <sys/conf.h> 64 #include <sys/fcntl.h> 65 #include <machine/clock.h> 66 #include <machine/ioctl_fd.h> 67 #include <sys/disklabel.h> 68 #include <sys/buf.h> 69 #include <sys/devicestat.h> 70 #include <sys/malloc.h> 71 #include <sys/proc.h> 72 #include <sys/syslog.h> 73 #include <i386/isa/isa.h> 74 #include <i386/isa/isa_device.h> 75 #include <i386/isa/fdreg.h> 76 #include <i386/isa/fdc.h> 77 #include <i386/isa/rtc.h> 78 #include <machine/stdarg.h> 79 #if NFT > 0 80 #include <sys/ftape.h> 81 #include <i386/isa/ftreg.h> 82 #endif 83 #ifdef DEVFS 84 #include <sys/devfsext.h> 85 #endif /* DEVFS */ 86 87 /* misuse a flag to identify format operation */ 88 #define B_FORMAT B_XXX 89 90 /* configuration flags */ 91 #define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */ 92 93 /* internally used only, not really from CMOS: */ 94 #define RTCFDT_144M_PRETENDED 0x1000 95 96 /* 97 * this biotab field doubles as a field for the physical unit number 98 * on the controller 99 */ 100 #define id_physid id_scsiid 101 102 /* error returns for fd_cmd() */ 103 #define FD_FAILED -1 104 #define FD_NOT_VALID -2 105 #define FDC_ERRMAX 100 /* do not log more */ 106 107 #define NUMTYPES 14 108 #define NUMDENS (NUMTYPES - 6) 109 110 /* These defines (-1) must match index for fd_types */ 111 #define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ 112 #define NO_TYPE 0 /* must match NO_TYPE in ft.c */ 113 #define FD_1720 1 114 #define FD_1480 2 115 #define FD_1440 3 116 #define FD_1200 4 117 #define FD_820 5 118 #define FD_800 6 119 #define FD_720 7 120 #define FD_360 8 121 122 #define FD_1480in5_25 9 123 #define FD_1440in5_25 10 124 #define FD_820in5_25 11 125 #define FD_800in5_25 12 126 #define FD_720in5_25 13 127 #define FD_360in5_25 14 128 129 130 static struct fd_type fd_types[NUMTYPES] = 131 { 132 { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ 133 { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ 134 { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ 135 { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ 136 { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ 137 { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ 138 { 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ 139 { 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ 140 141 { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ 142 { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ 143 { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ 144 { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ 145 { 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ 146 { 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ 147 }; 148 149 #define DRVS_PER_CTLR 2 /* 2 floppies */ 150 151 /***********************************************************************\ 152 * Per controller structure. * 153 \***********************************************************************/ 154 struct fdc_data fdc_data[NFDC]; 155 156 /***********************************************************************\ 157 * Per drive structure. * 158 * N per controller (DRVS_PER_CTLR) * 159 \***********************************************************************/ 160 static struct fd_data { 161 struct fdc_data *fdc; /* pointer to controller structure */ 162 int fdsu; /* this units number on this controller */ 163 int type; /* Drive type (FD_1440...) */ 164 struct fd_type *ft; /* pointer to the type descriptor */ 165 int flags; 166 #define FD_OPEN 0x01 /* it's open */ 167 #define FD_ACTIVE 0x02 /* it's active */ 168 #define FD_MOTOR 0x04 /* motor should be on */ 169 #define FD_MOTOR_WAIT 0x08 /* motor coming up */ 170 int skip; 171 int hddrv; 172 #define FD_NO_TRACK -2 173 int track; /* where we think the head is */ 174 int options; /* user configurable options, see ioctl_fd.h */ 175 struct callout_handle toffhandle; 176 struct callout_handle tohandle; 177 struct devstat device_stats; 178 #ifdef DEVFS 179 void *bdevs[1 + NUMDENS + MAXPARTITIONS]; 180 void *cdevs[1 + NUMDENS + MAXPARTITIONS]; 181 #endif 182 } fd_data[NFD]; 183 184 /***********************************************************************\ 185 * Throughout this file the following conventions will be used: * 186 * fd is a pointer to the fd_data struct for the drive in question * 187 * fdc is a pointer to the fdc_data struct for the controller * 188 * fdu is the floppy drive unit number * 189 * fdcu is the floppy controller unit number * 190 * fdsu is the floppy drive unit number on that controller. (sub-unit) * 191 \***********************************************************************/ 192 193 #if NFT > 0 194 int ftopen(dev_t, int); 195 int ftintr(ftu_t ftu); 196 int ftclose(dev_t, int); 197 void ftstrategy(struct buf *); 198 int ftioctl(dev_t, unsigned long, caddr_t, int, struct proc *); 199 int ftdump(dev_t); 200 int ftsize(dev_t); 201 int ftattach(struct isa_device *, struct isa_device *, int); 202 #endif 203 204 /* autoconfig functions */ 205 static int fdprobe(struct isa_device *); 206 static int fdattach(struct isa_device *); 207 208 /* needed for ft driver, thus exported */ 209 int in_fdc(fdcu_t); 210 int out_fdc(fdcu_t, int); 211 212 /* internal functions */ 213 static void set_motor(fdcu_t, int, int); 214 # define TURNON 1 215 # define TURNOFF 0 216 static timeout_t fd_turnoff; 217 static timeout_t fd_motor_on; 218 static void fd_turnon(fdu_t); 219 static void fdc_reset(fdc_p); 220 static int fd_in(fdcu_t, int *); 221 static void fdstart(fdcu_t); 222 static timeout_t fd_iotimeout; 223 static timeout_t fd_pseudointr; 224 static int fdstate(fdcu_t, fdc_p); 225 static int retrier(fdcu_t); 226 static int fdformat(dev_t, struct fd_formb *, struct proc *); 227 228 static int enable_fifo(fdc_p fdc); 229 230 static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */ 231 232 233 #define DEVIDLE 0 234 #define FINDWORK 1 235 #define DOSEEK 2 236 #define SEEKCOMPLETE 3 237 #define IOCOMPLETE 4 238 #define RECALCOMPLETE 5 239 #define STARTRECAL 6 240 #define RESETCTLR 7 241 #define SEEKWAIT 8 242 #define RECALWAIT 9 243 #define MOTORWAIT 10 244 #define IOTIMEDOUT 11 245 #define RESETCOMPLETE 12 246 247 #ifdef FDC_DEBUG 248 static char const * const fdstates[] = 249 { 250 "DEVIDLE", 251 "FINDWORK", 252 "DOSEEK", 253 "SEEKCOMPLETE", 254 "IOCOMPLETE", 255 "RECALCOMPLETE", 256 "STARTRECAL", 257 "RESETCTLR", 258 "SEEKWAIT", 259 "RECALWAIT", 260 "MOTORWAIT", 261 "IOTIMEDOUT", 262 "RESETCOMPLETE", 263 }; 264 265 /* CAUTION: fd_debug causes huge amounts of logging output */ 266 static int volatile fd_debug = 0; 267 #define TRACE0(arg) if(fd_debug) printf(arg) 268 #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) 269 #else /* FDC_DEBUG */ 270 #define TRACE0(arg) 271 #define TRACE1(arg1, arg2) 272 #endif /* FDC_DEBUG */ 273 274 /* autoconfig structure */ 275 276 struct isa_driver fdcdriver = { 277 fdprobe, fdattach, "fdc", 278 }; 279 280 static d_open_t Fdopen; /* NOTE, not fdopen */ 281 static d_read_t fdread; 282 static d_write_t fdwrite; 283 static d_close_t fdclose; 284 static d_ioctl_t fdioctl; 285 static d_strategy_t fdstrategy; 286 287 /* even if SLICE defined, these are needed for the ft support. */ 288 #define CDEV_MAJOR 9 289 #define BDEV_MAJOR 2 290 291 292 static struct cdevsw fd_cdevsw = { 293 Fdopen, fdclose, fdread, fdwrite, 294 fdioctl, nostop, nullreset, nodevtotty, 295 seltrue, nommap, fdstrategy, "fd", 296 NULL, -1, nodump, nopsize, 297 D_DISK, 0, -1 }; 298 299 300 static struct isa_device *fdcdevs[NFDC]; 301 302 303 static int 304 fdc_err(fdcu_t fdcu, const char *s) 305 { 306 fdc_data[fdcu].fdc_errs++; 307 if(s) { 308 if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX) 309 printf("fdc%d: %s", fdcu, s); 310 else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX) 311 printf("fdc%d: too many errors, not logging any more\n", 312 fdcu); 313 } 314 315 return FD_FAILED; 316 } 317 318 /* 319 * fd_cmd: Send a command to the chip. Takes a varargs with this structure: 320 * Unit number, 321 * # of output bytes, output bytes as ints ..., 322 * # of input bytes, input bytes as ints ... 323 */ 324 325 static int 326 fd_cmd(fdcu_t fdcu, int n_out, ...) 327 { 328 u_char cmd; 329 int n_in; 330 int n; 331 va_list ap; 332 333 va_start(ap, n_out); 334 cmd = (u_char)(va_arg(ap, int)); 335 va_end(ap); 336 va_start(ap, n_out); 337 for (n = 0; n < n_out; n++) 338 { 339 if (out_fdc(fdcu, va_arg(ap, int)) < 0) 340 { 341 char msg[50]; 342 sprintf(msg, 343 "cmd %x failed at out byte %d of %d\n", 344 cmd, n + 1, n_out); 345 return fdc_err(fdcu, msg); 346 } 347 } 348 n_in = va_arg(ap, int); 349 for (n = 0; n < n_in; n++) 350 { 351 int *ptr = va_arg(ap, int *); 352 if (fd_in(fdcu, ptr) < 0) 353 { 354 char msg[50]; 355 sprintf(msg, 356 "cmd %02x failed at in byte %d of %d\n", 357 cmd, n + 1, n_in); 358 return fdc_err(fdcu, msg); 359 } 360 } 361 362 return 0; 363 } 364 365 static int 366 enable_fifo(fdc_p fdc) 367 { 368 int i, j; 369 370 if ((fdc->flags & FDC_HAS_FIFO) == 0) { 371 372 /* 373 * XXX: 374 * Cannot use fd_cmd the normal way here, since 375 * this might be an invalid command. Thus we send the 376 * first byte, and check for an early turn of data directon. 377 */ 378 379 if (out_fdc(fdc->fdcu, I8207X_CONFIGURE) < 0) 380 return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); 381 382 /* If command is invalid, return */ 383 j = 100000; 384 while ((i = inb(fdc->baseport + FDSTS) & (NE7_DIO | NE7_RQM)) 385 != NE7_RQM && j-- > 0) 386 if (i == (NE7_DIO | NE7_RQM)) { 387 fdc_reset(fdc); 388 return FD_FAILED; 389 } 390 if (j<0 || 391 fd_cmd(fdc->fdcu, 3, 392 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) { 393 fdc_reset(fdc); 394 return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); 395 } 396 fdc->flags |= FDC_HAS_FIFO; 397 return 0; 398 } 399 if (fd_cmd(fdc->fdcu, 4, 400 I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) 401 return fdc_err(fdc->fdcu, "Re-enable FIFO failed\n"); 402 return 0; 403 } 404 405 static int 406 fd_sense_drive_status(fdc_p fdc, int *st3p) 407 { 408 int st3; 409 410 if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) 411 { 412 return fdc_err(fdc->fdcu, "Sense Drive Status failed\n"); 413 } 414 if (st3p) 415 *st3p = st3; 416 417 return 0; 418 } 419 420 static int 421 fd_sense_int(fdc_p fdc, int *st0p, int *cylp) 422 { 423 int st0, cyl; 424 425 int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0); 426 427 if (ret) 428 { 429 (void)fdc_err(fdc->fdcu, 430 "sense intr err reading stat reg 0\n"); 431 return ret; 432 } 433 434 if (st0p) 435 *st0p = st0; 436 437 if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) 438 { 439 /* 440 * There doesn't seem to have been an interrupt. 441 */ 442 return FD_NOT_VALID; 443 } 444 445 if (fd_in(fdc->fdcu, &cyl) < 0) 446 { 447 return fdc_err(fdc->fdcu, "can't get cyl num\n"); 448 } 449 450 if (cylp) 451 *cylp = cyl; 452 453 return 0; 454 } 455 456 457 static int 458 fd_read_status(fdc_p fdc, int fdsu) 459 { 460 int i, ret; 461 462 for (i = 0; i < 7; i++) 463 { 464 /* 465 * XXX types are poorly chosen. Only bytes can by read 466 * from the hardware, but fdc->status[] wants u_ints and 467 * fd_in() gives ints. 468 */ 469 int status; 470 471 ret = fd_in(fdc->fdcu, &status); 472 fdc->status[i] = status; 473 if (ret != 0) 474 break; 475 } 476 477 if (ret == 0) 478 fdc->flags |= FDC_STAT_VALID; 479 else 480 fdc->flags &= ~FDC_STAT_VALID; 481 482 return ret; 483 } 484 485 /****************************************************************************/ 486 /* autoconfiguration stuff */ 487 /****************************************************************************/ 488 489 /* 490 * probe for existance of controller 491 */ 492 static int 493 fdprobe(struct isa_device *dev) 494 { 495 fdcu_t fdcu = dev->id_unit; 496 if(fdc_data[fdcu].flags & FDC_ATTACHED) 497 { 498 printf("fdc%d: unit used multiple times\n", fdcu); 499 return 0; 500 } 501 502 fdcdevs[fdcu] = dev; 503 fdc_data[fdcu].baseport = dev->id_iobase; 504 505 /* First - lets reset the floppy controller */ 506 outb(dev->id_iobase+FDOUT, 0); 507 DELAY(100); 508 outb(dev->id_iobase+FDOUT, FDO_FRST); 509 510 /* see if it can handle a command */ 511 if (fd_cmd(fdcu, 512 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 513 0)) 514 { 515 return(0); 516 } 517 return (IO_FDCSIZE); 518 } 519 520 /* 521 * wire controller into system, look for floppy units 522 */ 523 static int 524 fdattach(struct isa_device *dev) 525 { 526 unsigned fdt; 527 fdu_t fdu; 528 fdcu_t fdcu = dev->id_unit; 529 fdc_p fdc = fdc_data + fdcu; 530 fd_p fd; 531 int fdsu, st0, st3, i; 532 #if NFT > 0 533 int unithasfd; 534 #endif 535 struct isa_device *fdup; 536 int ic_type = 0; 537 #ifdef DEVFS 538 int mynor; 539 int typemynor; 540 int typesize; 541 #endif 542 543 fdc->fdcu = fdcu; 544 fdc->flags |= FDC_ATTACHED; 545 fdc->dmachan = dev->id_drq; 546 /* Acquire the DMA channel forever, The driver will do the rest */ 547 isa_dma_acquire(fdc->dmachan); 548 isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */); 549 fdc->state = DEVIDLE; 550 /* reset controller, turn motor off, clear fdout mirror reg */ 551 outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); 552 bufq_init(&fdc->head); 553 554 /* check for each floppy drive */ 555 for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { 556 if (fdup->id_iobase != dev->id_iobase) 557 continue; 558 fdu = fdup->id_unit; 559 fd = &fd_data[fdu]; 560 if (fdu >= (NFD+NFT)) 561 continue; 562 fdsu = fdup->id_physid; 563 /* look up what bios thinks we have */ 564 switch (fdu) { 565 case 0: if (dev->id_flags & FDC_PRETEND_D0) 566 fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED; 567 else 568 fdt = (rtcin(RTC_FDISKETTE) & 0xf0); 569 break; 570 case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); 571 break; 572 default: fdt = RTCFDT_NONE; 573 break; 574 } 575 /* is there a unit? */ 576 if ((fdt == RTCFDT_NONE) 577 #if NFT > 0 578 || (fdsu >= DRVS_PER_CTLR)) { 579 #else 580 ) { 581 fd->type = NO_TYPE; 582 #endif 583 #if NFT > 0 584 /* If BIOS says no floppy, or > 2nd device */ 585 /* Probe for and attach a floppy tape. */ 586 /* Tell FT if there was already a disk */ 587 /* with this unit number found. */ 588 589 unithasfd = 0; 590 if (fdu < NFD && fd->type != NO_TYPE) 591 unithasfd = 1; 592 if (ftattach(dev, fdup, unithasfd)) 593 continue; 594 if (fdsu < DRVS_PER_CTLR) 595 fd->type = NO_TYPE; 596 #endif 597 continue; 598 } 599 600 /* select it */ 601 set_motor(fdcu, fdsu, TURNON); 602 DELAY(1000000); /* 1 sec */ 603 604 if (ic_type == 0 && 605 fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0) 606 { 607 #ifdef FDC_PRINT_BOGUS_CHIPTYPE 608 printf("fdc%d: ", fdcu); 609 #endif 610 ic_type = (u_char)ic_type; 611 switch( ic_type ) { 612 case 0x80: 613 #ifdef FDC_PRINT_BOGUS_CHIPTYPE 614 printf("NEC 765\n"); 615 #endif 616 fdc->fdct = FDC_NE765; 617 break; 618 case 0x81: 619 #ifdef FDC_PRINT_BOGUS_CHIPTYPE 620 printf("Intel 82077\n"); 621 #endif 622 fdc->fdct = FDC_I82077; 623 break; 624 case 0x90: 625 #ifdef FDC_PRINT_BOGUS_CHIPTYPE 626 printf("NEC 72065B\n"); 627 #endif 628 fdc->fdct = FDC_NE72065; 629 break; 630 default: 631 #ifdef FDC_PRINT_BOGUS_CHIPTYPE 632 printf("unknown IC type %02x\n", ic_type); 633 #endif 634 fdc->fdct = FDC_UNKNOWN; 635 break; 636 } 637 if (fdc->fdct != FDC_NE765 && 638 fdc->fdct != FDC_UNKNOWN && 639 enable_fifo(fdc) == 0) { 640 printf("fdc%d: FIFO enabled", fdcu); 641 printf(", %d bytes threshold\n", 642 fifo_threshold); 643 } 644 } 645 if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && 646 (st3 & NE7_ST3_T0)) { 647 /* if at track 0, first seek inwards */ 648 /* seek some steps: */ 649 (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); 650 DELAY(300000); /* ...wait a moment... */ 651 (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ 652 } 653 654 /* If we're at track 0 first seek inwards. */ 655 if ((fd_sense_drive_status(fdc, &st3) == 0) && 656 (st3 & NE7_ST3_T0)) { 657 /* Seek some steps... */ 658 if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { 659 /* ...wait a moment... */ 660 DELAY(300000); 661 /* make ctrlr happy: */ 662 (void)fd_sense_int(fdc, 0, 0); 663 } 664 } 665 666 for(i = 0; i < 2; i++) { 667 /* 668 * we must recalibrate twice, just in case the 669 * heads have been beyond cylinder 76, since most 670 * FDCs still barf when attempting to recalibrate 671 * more than 77 steps 672 */ 673 /* go back to 0: */ 674 if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { 675 /* a second being enough for full stroke seek*/ 676 DELAY(i == 0? 1000000: 300000); 677 678 /* anything responding? */ 679 if (fd_sense_int(fdc, &st0, 0) == 0 && 680 (st0 & NE7_ST0_EC) == 0) 681 break; /* already probed succesfully */ 682 } 683 } 684 685 set_motor(fdcu, fdsu, TURNOFF); 686 687 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ 688 continue; 689 690 fd->track = FD_NO_TRACK; 691 fd->fdc = fdc; 692 fd->fdsu = fdsu; 693 fd->options = 0; 694 callout_handle_init(&fd->toffhandle); 695 callout_handle_init(&fd->tohandle); 696 printf("fd%d: ", fdu); 697 698 switch (fdt) { 699 case RTCFDT_12M: 700 printf("1.2MB 5.25in\n"); 701 fd->type = FD_1200; 702 break; 703 case RTCFDT_144M | RTCFDT_144M_PRETENDED: 704 printf("config-pretended "); 705 fdt = RTCFDT_144M; 706 /* fallthrough */ 707 case RTCFDT_144M: 708 printf("1.44MB 3.5in\n"); 709 fd->type = FD_1440; 710 break; 711 case RTCFDT_288M: 712 case RTCFDT_288M_1: 713 printf("2.88MB 3.5in - 1.44MB mode\n"); 714 fd->type = FD_1440; 715 break; 716 case RTCFDT_360K: 717 printf("360KB 5.25in\n"); 718 fd->type = FD_360; 719 break; 720 case RTCFDT_720K: 721 printf("720KB 3.5in\n"); 722 fd->type = FD_720; 723 break; 724 default: 725 printf("unknown\n"); 726 fd->type = NO_TYPE; 727 continue; 728 } 729 #ifdef DEVFS 730 mynor = fdu << 6; 731 fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK, 732 UID_ROOT, GID_OPERATOR, 0640, 733 "fd%d", fdu); 734 fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, 735 UID_ROOT, GID_OPERATOR, 0640, 736 "rfd%d", fdu); 737 for (i = 1; i < 1 + NUMDENS; i++) { 738 /* 739 * XXX this and the lookup in Fdopen() should be 740 * data driven. 741 */ 742 switch (fd->type) { 743 case FD_360: 744 if (i != FD_360) 745 continue; 746 break; 747 case FD_720: 748 if (i != FD_720 && i != FD_800 && i != FD_820) 749 continue; 750 break; 751 case FD_1200: 752 if (i != FD_360 && i != FD_720 && i != FD_800 753 && i != FD_820 && i != FD_1200 754 && i != FD_1440 && i != FD_1480) 755 continue; 756 break; 757 case FD_1440: 758 if (i != FD_720 && i != FD_800 && i != FD_820 759 && i != FD_1200 && i != FD_1440 760 && i != FD_1480 && i != FD_1720) 761 continue; 762 break; 763 } 764 typesize = fd_types[i - 1].size / 2; 765 /* 766 * XXX all these conversions give bloated code and 767 * confusing names. 768 */ 769 if (typesize == 1476) 770 typesize = 1480; 771 if (typesize == 1722) 772 typesize = 1720; 773 typemynor = mynor | i; 774 fd->bdevs[i] = 775 devfs_add_devswf(&fd_cdevsw, typemynor, DV_BLK, 776 UID_ROOT, GID_OPERATOR, 0640, 777 "fd%d.%d", fdu, typesize); 778 fd->cdevs[i] = 779 devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR, 780 UID_ROOT, GID_OPERATOR, 0640, 781 "rfd%d.%d", fdu, typesize); 782 } 783 784 for (i = 0; i < MAXPARTITIONS; i++) { 785 fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0], 786 "fd%d%c", fdu, 'a' + i); 787 fd->cdevs[1 + NUMDENS + i] = 788 devfs_link(fd->cdevs[0], 789 "rfd%d%c", fdu, 'a' + i); 790 } 791 #endif /* DEVFS */ 792 /* 793 * Export the drive to the devstat interface. 794 */ 795 devstat_add_entry(&fd->device_stats, "fd", 796 fdu, 512, 797 DEVSTAT_NO_ORDERED_TAGS, 798 DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER); 799 800 } 801 802 return (1); 803 } 804 805 806 807 /****************************************************************************/ 808 /* motor control stuff */ 809 /* remember to not deselect the drive we're working on */ 810 /****************************************************************************/ 811 static void 812 set_motor(fdcu_t fdcu, int fdsu, int turnon) 813 { 814 int fdout = fdc_data[fdcu].fdout; 815 int needspecify = 0; 816 817 if(turnon) { 818 fdout &= ~FDO_FDSEL; 819 fdout |= (FDO_MOEN0 << fdsu) + fdsu; 820 } else 821 fdout &= ~(FDO_MOEN0 << fdsu); 822 823 if(!turnon 824 && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) 825 /* gonna turn off the last drive, put FDC to bed */ 826 fdout &= ~ (FDO_FRST|FDO_FDMAEN); 827 else { 828 /* make sure controller is selected and specified */ 829 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) 830 needspecify = 1; 831 fdout |= (FDO_FRST|FDO_FDMAEN); 832 } 833 834 outb(fdc_data[fdcu].baseport+FDOUT, fdout); 835 fdc_data[fdcu].fdout = fdout; 836 TRACE1("[0x%x->FDOUT]", fdout); 837 838 if(needspecify) { 839 /* 840 * XXX 841 * special case: since we have just woken up the FDC 842 * from its sleep, we silently assume the command will 843 * be accepted, and do not test for a timeout 844 */ 845 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 846 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 847 0); 848 if (fdc_data[fdcu].flags & FDC_HAS_FIFO) 849 (void) enable_fifo(&fdc_data[fdcu]); 850 } 851 } 852 853 static void 854 fd_turnoff(void *arg1) 855 { 856 fdu_t fdu = (fdu_t)arg1; 857 int s; 858 fd_p fd = fd_data + fdu; 859 860 TRACE1("[fd%d: turnoff]", fdu); 861 862 /* 863 * Don't turn off the motor yet if the drive is active. 864 * XXX shouldn't even schedule turnoff until drive is inactive 865 * and nothing is queued on it. 866 */ 867 if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) { 868 fd->toffhandle = timeout(fd_turnoff, arg1, 4 * hz); 869 return; 870 } 871 872 s = splbio(); 873 fd->flags &= ~FD_MOTOR; 874 set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); 875 splx(s); 876 } 877 878 static void 879 fd_motor_on(void *arg1) 880 { 881 fdu_t fdu = (fdu_t)arg1; 882 int s; 883 884 fd_p fd = fd_data + fdu; 885 s = splbio(); 886 fd->flags &= ~FD_MOTOR_WAIT; 887 if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 888 { 889 fdintr(fd->fdc->fdcu); 890 } 891 splx(s); 892 } 893 894 static void 895 fd_turnon(fdu_t fdu) 896 { 897 fd_p fd = fd_data + fdu; 898 if(!(fd->flags & FD_MOTOR)) 899 { 900 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); 901 set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); 902 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ 903 } 904 } 905 906 static void 907 fdc_reset(fdc_p fdc) 908 { 909 fdcu_t fdcu = fdc->fdcu; 910 911 /* Try a reset, keep motor on */ 912 outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 913 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 914 DELAY(100); 915 /* enable FDC, but defer interrupts a moment */ 916 outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); 917 TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); 918 DELAY(100); 919 outb(fdc->baseport + FDOUT, fdc->fdout); 920 TRACE1("[0x%x->FDOUT]", fdc->fdout); 921 922 /* XXX after a reset, silently believe the FDC will accept commands */ 923 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, 924 NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 925 0); 926 if (fdc->flags & FDC_HAS_FIFO) 927 (void) enable_fifo(fdc); 928 } 929 930 /****************************************************************************/ 931 /* fdc in/out */ 932 /****************************************************************************/ 933 int 934 in_fdc(fdcu_t fdcu) 935 { 936 int baseport = fdc_data[fdcu].baseport; 937 int i, j = 100000; 938 while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 939 != (NE7_DIO|NE7_RQM) && j-- > 0) 940 if (i == NE7_RQM) 941 return fdc_err(fdcu, "ready for output in input\n"); 942 if (j <= 0) 943 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 944 #ifdef FDC_DEBUG 945 i = inb(baseport+FDDATA); 946 TRACE1("[FDDATA->0x%x]", (unsigned char)i); 947 return(i); 948 #else /* !FDC_DEBUG */ 949 return inb(baseport+FDDATA); 950 #endif /* FDC_DEBUG */ 951 } 952 953 /* 954 * fd_in: Like in_fdc, but allows you to see if it worked. 955 */ 956 static int 957 fd_in(fdcu_t fdcu, int *ptr) 958 { 959 int baseport = fdc_data[fdcu].baseport; 960 int i, j = 100000; 961 while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) 962 != (NE7_DIO|NE7_RQM) && j-- > 0) 963 if (i == NE7_RQM) 964 return fdc_err(fdcu, "ready for output in input\n"); 965 if (j <= 0) 966 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); 967 #ifdef FDC_DEBUG 968 i = inb(baseport+FDDATA); 969 TRACE1("[FDDATA->0x%x]", (unsigned char)i); 970 *ptr = i; 971 return 0; 972 #else /* !FDC_DEBUG */ 973 i = inb(baseport+FDDATA); 974 if (ptr) 975 *ptr = i; 976 return 0; 977 #endif /* FDC_DEBUG */ 978 } 979 980 int 981 out_fdc(fdcu_t fdcu, int x) 982 { 983 int baseport = fdc_data[fdcu].baseport; 984 int i; 985 986 /* Check that the direction bit is set */ 987 i = 100000; 988 while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); 989 if (i <= 0) return fdc_err(fdcu, "direction bit not set\n"); 990 991 /* Check that the floppy controller is ready for a command */ 992 i = 100000; 993 while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); 994 if (i <= 0) 995 return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0); 996 997 /* Send the command and return */ 998 outb(baseport+FDDATA, x); 999 TRACE1("[0x%x->FDDATA]", x); 1000 return (0); 1001 } 1002 1003 /****************************************************************************/ 1004 /* fdopen/fdclose */ 1005 /****************************************************************************/ 1006 int 1007 Fdopen(dev_t dev, int flags, int mode, struct proc *p) 1008 { 1009 fdu_t fdu = FDUNIT(minor(dev)); 1010 int type = FDTYPE(minor(dev)); 1011 fdc_p fdc; 1012 1013 #if NFT > 0 1014 /* check for a tape open */ 1015 if (type & F_TAPE_TYPE) 1016 return(ftopen(dev, flags)); 1017 #endif 1018 /* check bounds */ 1019 if (fdu >= NFD) 1020 return(ENXIO); 1021 fdc = fd_data[fdu].fdc; 1022 if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) 1023 return(ENXIO); 1024 if (type > NUMDENS) 1025 return(ENXIO); 1026 if (type == 0) 1027 type = fd_data[fdu].type; 1028 else { 1029 /* 1030 * For each type of basic drive, make sure we are trying 1031 * to open a type it can do, 1032 */ 1033 if (type != fd_data[fdu].type) { 1034 switch (fd_data[fdu].type) { 1035 case FD_360: 1036 return(ENXIO); 1037 case FD_720: 1038 if ( type != FD_820 1039 && type != FD_800 1040 ) 1041 return(ENXIO); 1042 break; 1043 case FD_1200: 1044 switch (type) { 1045 case FD_1480: 1046 type = FD_1480in5_25; 1047 break; 1048 case FD_1440: 1049 type = FD_1440in5_25; 1050 break; 1051 case FD_820: 1052 type = FD_820in5_25; 1053 break; 1054 case FD_800: 1055 type = FD_800in5_25; 1056 break; 1057 case FD_720: 1058 type = FD_720in5_25; 1059 break; 1060 case FD_360: 1061 type = FD_360in5_25; 1062 break; 1063 default: 1064 return(ENXIO); 1065 } 1066 break; 1067 case FD_1440: 1068 if ( type != FD_1720 1069 && type != FD_1480 1070 && type != FD_1200 1071 && type != FD_820 1072 && type != FD_800 1073 && type != FD_720 1074 ) 1075 return(ENXIO); 1076 break; 1077 } 1078 } 1079 } 1080 fd_data[fdu].ft = fd_types + type - 1; 1081 fd_data[fdu].flags |= FD_OPEN; 1082 1083 return 0; 1084 } 1085 1086 int 1087 fdclose(dev_t dev, int flags, int mode, struct proc *p) 1088 { 1089 fdu_t fdu = FDUNIT(minor(dev)); 1090 1091 #if NFT > 0 1092 int type = FDTYPE(minor(dev)); 1093 1094 if (type & F_TAPE_TYPE) 1095 return ftclose(dev, flags); 1096 #endif 1097 fd_data[fdu].flags &= ~FD_OPEN; 1098 fd_data[fdu].options &= ~FDOPT_NORETRY; 1099 1100 return(0); 1101 } 1102 1103 static int 1104 fdread(dev_t dev, struct uio *uio, int ioflag) 1105 { 1106 return (physio(fdstrategy, NULL, dev, 1, minphys, uio)); 1107 } 1108 1109 static int 1110 fdwrite(dev_t dev, struct uio *uio, int ioflag) 1111 { 1112 return (physio(fdstrategy, NULL, dev, 0, minphys, uio)); 1113 } 1114 1115 1116 /****************************************************************************/ 1117 /* fdstrategy */ 1118 /****************************************************************************/ 1119 void 1120 fdstrategy(struct buf *bp) 1121 { 1122 unsigned nblocks, blknum, cando; 1123 int s; 1124 fdcu_t fdcu; 1125 fdu_t fdu; 1126 fdc_p fdc; 1127 fd_p fd; 1128 size_t fdblk; 1129 1130 fdu = FDUNIT(minor(bp->b_dev)); 1131 fd = &fd_data[fdu]; 1132 fdc = fd->fdc; 1133 fdcu = fdc->fdcu; 1134 1135 #if NFT > 0 1136 if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) { 1137 /* ft tapes do not (yet) support strategy i/o */ 1138 bp->b_error = ENODEV; 1139 bp->b_flags |= B_ERROR; 1140 goto bad; 1141 } 1142 /* check for controller already busy with tape */ 1143 if (fdc->flags & FDC_TAPE_BUSY) { 1144 bp->b_error = EBUSY; 1145 bp->b_flags |= B_ERROR; 1146 goto bad; 1147 } 1148 #endif 1149 fdblk = 128 << (fd->ft->secsize); 1150 if (!(bp->b_flags & B_FORMAT)) { 1151 if ((fdu >= NFD) || (bp->b_blkno < 0)) { 1152 printf( 1153 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n", 1154 fdu, (u_long)bp->b_blkno, bp->b_bcount); 1155 bp->b_error = EINVAL; 1156 bp->b_flags |= B_ERROR; 1157 goto bad; 1158 } 1159 if ((bp->b_bcount % fdblk) != 0) { 1160 bp->b_error = EINVAL; 1161 bp->b_flags |= B_ERROR; 1162 goto bad; 1163 } 1164 } 1165 1166 /* 1167 * Set up block calculations. 1168 */ 1169 if (bp->b_blkno > 20000000) { 1170 /* 1171 * Reject unreasonably high block number, prevent the 1172 * multiplication below from overflowing. 1173 */ 1174 bp->b_error = EINVAL; 1175 bp->b_flags |= B_ERROR; 1176 goto bad; 1177 } 1178 blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk; 1179 nblocks = fd->ft->size; 1180 bp->b_resid = 0; 1181 if (blknum + (bp->b_bcount / fdblk) > nblocks) { 1182 if (blknum <= nblocks) { 1183 cando = (nblocks - blknum) * fdblk; 1184 bp->b_resid = bp->b_bcount - cando; 1185 if (cando == 0) 1186 goto bad; /* not actually bad but EOF */ 1187 } else { 1188 bp->b_error = EINVAL; 1189 bp->b_flags |= B_ERROR; 1190 goto bad; 1191 } 1192 } 1193 bp->b_pblkno = bp->b_blkno; 1194 s = splbio(); 1195 bufqdisksort(&fdc->head, bp); 1196 untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ 1197 1198 /* Tell devstat we are starting on the transaction */ 1199 devstat_start_transaction(&fd->device_stats); 1200 1201 fdstart(fdcu); 1202 splx(s); 1203 return; 1204 1205 bad: 1206 biodone(bp); 1207 } 1208 1209 /***************************************************************\ 1210 * fdstart * 1211 * We have just queued something.. if the controller is not busy * 1212 * then simulate the case where it has just finished a command * 1213 * So that it (the interrupt routine) looks on the queue for more* 1214 * work to do and picks up what we just added. * 1215 * If the controller is already busy, we need do nothing, as it * 1216 * will pick up our work when the present work completes * 1217 \***************************************************************/ 1218 static void 1219 fdstart(fdcu_t fdcu) 1220 { 1221 int s; 1222 1223 s = splbio(); 1224 if(fdc_data[fdcu].state == DEVIDLE) 1225 { 1226 fdintr(fdcu); 1227 } 1228 splx(s); 1229 } 1230 1231 static void 1232 fd_iotimeout(void *arg1) 1233 { 1234 fdc_p fdc; 1235 fdcu_t fdcu; 1236 int s; 1237 1238 fdcu = (fdcu_t)arg1; 1239 fdc = fdc_data + fdcu; 1240 TRACE1("fd%d[fd_iotimeout()]", fdc->fdu); 1241 1242 /* 1243 * Due to IBM's brain-dead design, the FDC has a faked ready 1244 * signal, hardwired to ready == true. Thus, any command 1245 * issued if there's no diskette in the drive will _never_ 1246 * complete, and must be aborted by resetting the FDC. 1247 * Many thanks, Big Blue! 1248 * The FDC must not be reset directly, since that would 1249 * interfere with the state machine. Instead, pretend that 1250 * the command completed but was invalid. The state machine 1251 * will reset the FDC and retry once. 1252 */ 1253 s = splbio(); 1254 fdc->status[0] = NE7_ST0_IC_IV; 1255 fdc->flags &= ~FDC_STAT_VALID; 1256 fdc->state = IOTIMEDOUT; 1257 fdintr(fdcu); 1258 splx(s); 1259 } 1260 1261 /* just ensure it has the right spl */ 1262 static void 1263 fd_pseudointr(void *arg1) 1264 { 1265 fdcu_t fdcu = (fdcu_t)arg1; 1266 int s; 1267 1268 s = splbio(); 1269 fdintr(fdcu); 1270 splx(s); 1271 } 1272 1273 /***********************************************************************\ 1274 * fdintr * 1275 * keep calling the state machine until it returns a 0 * 1276 * ALWAYS called at SPLBIO * 1277 \***********************************************************************/ 1278 void 1279 fdintr(fdcu_t fdcu) 1280 { 1281 fdc_p fdc = fdc_data + fdcu; 1282 #if NFT > 0 1283 fdu_t fdu = fdc->fdu; 1284 1285 if (fdc->flags & FDC_TAPE_BUSY) 1286 (ftintr(fdu)); 1287 else 1288 #endif 1289 while(fdstate(fdcu, fdc)) 1290 ; 1291 } 1292 1293 /***********************************************************************\ 1294 * The controller state machine. * 1295 * if it returns a non zero value, it should be called again immediatly * 1296 \***********************************************************************/ 1297 static int 1298 fdstate(fdcu_t fdcu, fdc_p fdc) 1299 { 1300 struct subdev *sd; 1301 int read, format, head, i, sec = 0, sectrac, st0, cyl, st3; 1302 unsigned blknum = 0, b_cylinder = 0; 1303 fdu_t fdu = fdc->fdu; 1304 fd_p fd; 1305 register struct buf *bp; 1306 struct fd_formb *finfo = NULL; 1307 size_t fdblk; 1308 1309 bp = bufq_first(&fdc->head); 1310 if(!bp) { 1311 /***********************************************\ 1312 * nothing left for this controller to do * 1313 * Force into the IDLE state, * 1314 \***********************************************/ 1315 fdc->state = DEVIDLE; 1316 if(fdc->fd) 1317 { 1318 printf("fd%d: unexpected valid fd pointer\n", 1319 fdc->fdu); 1320 fdc->fd = (fd_p) 0; 1321 fdc->fdu = -1; 1322 } 1323 TRACE1("[fdc%d IDLE]", fdcu); 1324 return(0); 1325 } 1326 fdu = FDUNIT(minor(bp->b_dev)); 1327 fd = fd_data + fdu; 1328 fdblk = 128 << fd->ft->secsize; 1329 if (fdc->fd && (fd != fdc->fd)) 1330 { 1331 printf("fd%d: confused fd pointers\n", fdu); 1332 } 1333 read = bp->b_flags & B_READ; 1334 format = bp->b_flags & B_FORMAT; 1335 if(format) { 1336 finfo = (struct fd_formb *)bp->b_data; 1337 fd->skip = (char *)&(finfo->fd_formb_cylno(0)) 1338 - (char *)finfo; 1339 } 1340 if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { 1341 blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + 1342 fd->skip/fdblk; 1343 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); 1344 } 1345 TRACE1("fd%d", fdu); 1346 TRACE1("[%s]", fdstates[fdc->state]); 1347 TRACE1("(0x%x)", fd->flags); 1348 untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); 1349 fd->toffhandle = timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); 1350 switch (fdc->state) 1351 { 1352 case DEVIDLE: 1353 case FINDWORK: /* we have found new work */ 1354 fdc->retry = 0; 1355 fd->skip = 0; 1356 fdc->fd = fd; 1357 fdc->fdu = fdu; 1358 outb(fdc->baseport+FDCTL, fd->ft->trans); 1359 TRACE1("[0x%x->FDCTL]", fd->ft->trans); 1360 /*******************************************************\ 1361 * If the next drive has a motor startup pending, then * 1362 * it will start up in its own good time * 1363 \*******************************************************/ 1364 if(fd->flags & FD_MOTOR_WAIT) 1365 { 1366 fdc->state = MOTORWAIT; 1367 return(0); /* come back later */ 1368 } 1369 /*******************************************************\ 1370 * Maybe if it's not starting, it SHOULD be starting * 1371 \*******************************************************/ 1372 if (!(fd->flags & FD_MOTOR)) 1373 { 1374 fdc->state = MOTORWAIT; 1375 fd_turnon(fdu); 1376 return(0); 1377 } 1378 else /* at least make sure we are selected */ 1379 { 1380 set_motor(fdcu, fd->fdsu, TURNON); 1381 } 1382 if (fdc->flags & FDC_NEEDS_RESET) { 1383 fdc->state = RESETCTLR; 1384 fdc->flags &= ~FDC_NEEDS_RESET; 1385 } else 1386 fdc->state = DOSEEK; 1387 break; 1388 case DOSEEK: 1389 if (b_cylinder == (unsigned)fd->track) 1390 { 1391 fdc->state = SEEKCOMPLETE; 1392 break; 1393 } 1394 if (fd_cmd(fdcu, 3, NE7CMD_SEEK, 1395 fd->fdsu, b_cylinder * fd->ft->steptrac, 1396 0)) 1397 { 1398 /* 1399 * seek command not accepted, looks like 1400 * the FDC went off to the Saints... 1401 */ 1402 fdc->retry = 6; /* try a reset */ 1403 return(retrier(fdcu)); 1404 } 1405 fd->track = FD_NO_TRACK; 1406 fdc->state = SEEKWAIT; 1407 return(0); /* will return later */ 1408 case SEEKWAIT: 1409 /* allow heads to settle */ 1410 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16); 1411 fdc->state = SEEKCOMPLETE; 1412 return(0); /* will return later */ 1413 case SEEKCOMPLETE : /* SEEK DONE, START DMA */ 1414 /* Make sure seek really happened*/ 1415 if(fd->track == FD_NO_TRACK) 1416 { 1417 int descyl = b_cylinder * fd->ft->steptrac; 1418 do { 1419 /* 1420 * This might be a "ready changed" interrupt, 1421 * which cannot really happen since the 1422 * RDY pin is hardwired to + 5 volts. This 1423 * generally indicates a "bouncing" intr 1424 * line, so do one of the following: 1425 * 1426 * When running on an enhanced FDC that is 1427 * known to not go stuck after responding 1428 * with INVALID, fetch all interrupt states 1429 * until seeing either an INVALID or a 1430 * real interrupt condition. 1431 * 1432 * When running on a dumb old NE765, give 1433 * up immediately. The controller will 1434 * provide up to four dummy RC interrupt 1435 * conditions right after reset (for the 1436 * corresponding four drives), so this is 1437 * our only chance to get notice that it 1438 * was not the FDC that caused the interrupt. 1439 */ 1440 if (fd_sense_int(fdc, &st0, &cyl) 1441 == FD_NOT_VALID) 1442 return 0; 1443 if(fdc->fdct == FDC_NE765 1444 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1445 return 0; /* hope for a real intr */ 1446 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1447 1448 if (0 == descyl) 1449 { 1450 int failed = 0; 1451 /* 1452 * seek to cyl 0 requested; make sure we are 1453 * really there 1454 */ 1455 if (fd_sense_drive_status(fdc, &st3)) 1456 failed = 1; 1457 if ((st3 & NE7_ST3_T0) == 0) { 1458 printf( 1459 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", 1460 fdu, st3, NE7_ST3BITS); 1461 failed = 1; 1462 } 1463 1464 if (failed) 1465 { 1466 if(fdc->retry < 3) 1467 fdc->retry = 3; 1468 return(retrier(fdcu)); 1469 } 1470 } 1471 1472 if (cyl != descyl) 1473 { 1474 printf( 1475 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", 1476 fdu, descyl, cyl, st0); 1477 if (fdc->retry < 3) 1478 fdc->retry = 3; 1479 return(retrier(fdcu)); 1480 } 1481 } 1482 1483 fd->track = b_cylinder; 1484 isa_dmastart(bp->b_flags, bp->b_data+fd->skip, 1485 format ? bp->b_bcount : fdblk, fdc->dmachan); 1486 sectrac = fd->ft->sectrac; 1487 sec = blknum % (sectrac * fd->ft->heads); 1488 head = sec / sectrac; 1489 sec = sec % sectrac + 1; 1490 fd->hddrv = ((head&1)<<2)+fdu; 1491 1492 if(format || !read) 1493 { 1494 /* make sure the drive is writable */ 1495 if(fd_sense_drive_status(fdc, &st3) != 0) 1496 { 1497 /* stuck controller? */ 1498 isa_dmadone(bp->b_flags, bp->b_data + fd->skip, 1499 format ? bp->b_bcount : fdblk, 1500 fdc->dmachan); 1501 fdc->retry = 6; /* reset the beast */ 1502 return(retrier(fdcu)); 1503 } 1504 if(st3 & NE7_ST3_WP) 1505 { 1506 /* 1507 * XXX YES! this is ugly. 1508 * in order to force the current operation 1509 * to fail, we will have to fake an FDC 1510 * error - all error handling is done 1511 * by the retrier() 1512 */ 1513 fdc->status[0] = NE7_ST0_IC_AT; 1514 fdc->status[1] = NE7_ST1_NW; 1515 fdc->status[2] = 0; 1516 fdc->status[3] = fd->track; 1517 fdc->status[4] = head; 1518 fdc->status[5] = sec; 1519 fdc->retry = 8; /* break out immediately */ 1520 fdc->state = IOTIMEDOUT; /* not really... */ 1521 return (1); 1522 } 1523 } 1524 1525 if(format) 1526 { 1527 /* formatting */ 1528 if(fd_cmd(fdcu, 6, 1529 NE7CMD_FORMAT, 1530 head << 2 | fdu, 1531 finfo->fd_formb_secshift, 1532 finfo->fd_formb_nsecs, 1533 finfo->fd_formb_gaplen, 1534 finfo->fd_formb_fillbyte, 1535 0)) 1536 { 1537 /* controller fell over */ 1538 isa_dmadone(bp->b_flags, bp->b_data + fd->skip, 1539 format ? bp->b_bcount : fdblk, 1540 fdc->dmachan); 1541 fdc->retry = 6; 1542 return(retrier(fdcu)); 1543 } 1544 } 1545 else 1546 { 1547 if (fd_cmd(fdcu, 9, 1548 (read ? NE7CMD_READ : NE7CMD_WRITE), 1549 head << 2 | fdu, /* head & unit */ 1550 fd->track, /* track */ 1551 head, 1552 sec, /* sector + 1 */ 1553 fd->ft->secsize, /* sector size */ 1554 sectrac, /* sectors/track */ 1555 fd->ft->gap, /* gap size */ 1556 fd->ft->datalen, /* data length */ 1557 0)) 1558 { 1559 /* the beast is sleeping again */ 1560 isa_dmadone(bp->b_flags, bp->b_data + fd->skip, 1561 format ? bp->b_bcount : fdblk, 1562 fdc->dmachan); 1563 fdc->retry = 6; 1564 return(retrier(fdcu)); 1565 } 1566 } 1567 fdc->state = IOCOMPLETE; 1568 fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz); 1569 return(0); /* will return later */ 1570 case IOCOMPLETE: /* IO DONE, post-analyze */ 1571 untimeout(fd_iotimeout, (caddr_t)fdcu, fd->tohandle); 1572 1573 if (fd_read_status(fdc, fd->fdsu)) 1574 { 1575 isa_dmadone(bp->b_flags, bp->b_data + fd->skip, 1576 format ? bp->b_bcount : fdblk, 1577 fdc->dmachan); 1578 if (fdc->retry < 6) 1579 fdc->retry = 6; /* force a reset */ 1580 return retrier(fdcu); 1581 } 1582 1583 fdc->state = IOTIMEDOUT; 1584 1585 /* FALLTHROUGH */ 1586 1587 case IOTIMEDOUT: 1588 isa_dmadone(bp->b_flags, bp->b_data + fd->skip, 1589 format ? bp->b_bcount : fdblk, fdc->dmachan); 1590 if (fdc->status[0] & NE7_ST0_IC) 1591 { 1592 if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1593 && fdc->status[1] & NE7_ST1_OR) { 1594 /* 1595 * DMA overrun. Someone hogged the bus 1596 * and didn't release it in time for the 1597 * next FDC transfer. 1598 * Just restart it, don't increment retry 1599 * count. (vak) 1600 */ 1601 fdc->state = SEEKCOMPLETE; 1602 return (1); 1603 } 1604 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV 1605 && fdc->retry < 6) 1606 fdc->retry = 6; /* force a reset */ 1607 else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 1608 && fdc->status[2] & NE7_ST2_WC 1609 && fdc->retry < 3) 1610 fdc->retry = 3; /* force recalibrate */ 1611 return(retrier(fdcu)); 1612 } 1613 /* All OK */ 1614 fd->skip += fdblk; 1615 if (!format && fd->skip < bp->b_bcount - bp->b_resid) 1616 { 1617 /* set up next transfer */ 1618 fdc->state = DOSEEK; 1619 } 1620 else 1621 { 1622 /* ALL DONE */ 1623 fd->skip = 0; 1624 bufq_remove(&fdc->head, bp); 1625 /* Tell devstat we have finished with the transaction */ 1626 devstat_end_transaction(&fd->device_stats, 1627 bp->b_bcount - bp->b_resid, 1628 DEVSTAT_TAG_NONE, 1629 (bp->b_flags & B_READ) ? 1630 DEVSTAT_READ : DEVSTAT_WRITE); 1631 biodone(bp); 1632 fdc->fd = (fd_p) 0; 1633 fdc->fdu = -1; 1634 fdc->state = FINDWORK; 1635 } 1636 return(1); 1637 case RESETCTLR: 1638 fdc_reset(fdc); 1639 fdc->retry++; 1640 fdc->state = RESETCOMPLETE; 1641 return (0); 1642 case RESETCOMPLETE: 1643 /* 1644 * Discard all the results from the reset so that they 1645 * can't cause an unexpected interrupt later. 1646 */ 1647 for (i = 0; i < 4; i++) 1648 (void)fd_sense_int(fdc, &st0, &cyl); 1649 fdc->state = STARTRECAL; 1650 /* Fall through. */ 1651 case STARTRECAL: 1652 if(fd_cmd(fdcu, 1653 2, NE7CMD_RECAL, fdu, 1654 0)) /* Recalibrate Function */ 1655 { 1656 /* arrgl */ 1657 fdc->retry = 6; 1658 return(retrier(fdcu)); 1659 } 1660 fdc->state = RECALWAIT; 1661 return(0); /* will return later */ 1662 case RECALWAIT: 1663 /* allow heads to settle */ 1664 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8); 1665 fdc->state = RECALCOMPLETE; 1666 return(0); /* will return later */ 1667 case RECALCOMPLETE: 1668 do { 1669 /* 1670 * See SEEKCOMPLETE for a comment on this: 1671 */ 1672 if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) 1673 return 0; 1674 if(fdc->fdct == FDC_NE765 1675 && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 1676 return 0; /* hope for a real intr */ 1677 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 1678 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) 1679 { 1680 if(fdc->retry > 3) 1681 /* 1682 * a recalibrate from beyond cylinder 77 1683 * will "fail" due to the FDC limitations; 1684 * since people used to complain much about 1685 * the failure message, try not logging 1686 * this one if it seems to be the first 1687 * time in a line 1688 */ 1689 printf("fd%d: recal failed ST0 %b cyl %d\n", 1690 fdu, st0, NE7_ST0BITS, cyl); 1691 if(fdc->retry < 3) fdc->retry = 3; 1692 return(retrier(fdcu)); 1693 } 1694 fd->track = 0; 1695 /* Seek (probably) necessary */ 1696 fdc->state = DOSEEK; 1697 return(1); /* will return immediatly */ 1698 case MOTORWAIT: 1699 if(fd->flags & FD_MOTOR_WAIT) 1700 { 1701 return(0); /* time's not up yet */ 1702 } 1703 if (fdc->flags & FDC_NEEDS_RESET) { 1704 fdc->state = RESETCTLR; 1705 fdc->flags &= ~FDC_NEEDS_RESET; 1706 } else { 1707 /* 1708 * If all motors were off, then the controller was 1709 * reset, so it has lost track of the current 1710 * cylinder. Recalibrate to handle this case. 1711 */ 1712 fdc->state = STARTRECAL; 1713 } 1714 return(1); /* will return immediatly */ 1715 default: 1716 printf("fdc%d: Unexpected FD int->", fdcu); 1717 if (fd_read_status(fdc, fd->fdsu) == 0) 1718 printf("FDC status :%x %x %x %x %x %x %x ", 1719 fdc->status[0], 1720 fdc->status[1], 1721 fdc->status[2], 1722 fdc->status[3], 1723 fdc->status[4], 1724 fdc->status[5], 1725 fdc->status[6] ); 1726 else 1727 printf("No status available "); 1728 if (fd_sense_int(fdc, &st0, &cyl) != 0) 1729 { 1730 printf("[controller is dead now]\n"); 1731 return(0); 1732 } 1733 printf("ST0 = %x, PCN = %x\n", st0, cyl); 1734 return(0); 1735 } 1736 /*XXX confusing: some branches return immediately, others end up here*/ 1737 return(1); /* Come back immediatly to new state */ 1738 } 1739 1740 static int 1741 retrier(fdcu) 1742 fdcu_t fdcu; 1743 { 1744 struct subdev *sd; 1745 fdc_p fdc = fdc_data + fdcu; 1746 register struct buf *bp; 1747 int fdu; 1748 1749 bp = bufq_first(&fdc->head); 1750 1751 if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) 1752 goto fail; 1753 switch(fdc->retry) 1754 { 1755 case 0: case 1: case 2: 1756 fdc->state = SEEKCOMPLETE; 1757 break; 1758 case 3: case 4: case 5: 1759 fdc->state = STARTRECAL; 1760 break; 1761 case 6: 1762 fdc->state = RESETCTLR; 1763 break; 1764 case 7: 1765 break; 1766 default: 1767 fail: 1768 { 1769 dev_t sav_b_dev = bp->b_dev; 1770 /* Trick diskerr */ 1771 bp->b_dev = makedev(major(bp->b_dev), 1772 (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); 1773 diskerr(bp, "fd", "hard error", LOG_PRINTF, 1774 fdc->fd->skip / DEV_BSIZE, 1775 (struct disklabel *)NULL); 1776 bp->b_dev = sav_b_dev; 1777 if (fdc->flags & FDC_STAT_VALID) 1778 { 1779 printf( 1780 " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n", 1781 fdc->status[0], NE7_ST0BITS, 1782 fdc->status[1], NE7_ST1BITS, 1783 fdc->status[2], NE7_ST2BITS, 1784 fdc->status[3], fdc->status[4], 1785 fdc->status[5]); 1786 } 1787 else 1788 printf(" (No status)\n"); 1789 } 1790 bp->b_flags |= B_ERROR; 1791 bp->b_error = EIO; 1792 bp->b_resid += bp->b_bcount - fdc->fd->skip; 1793 bufq_remove(&fdc->head, bp); 1794 1795 /* Tell devstat we have finished with the transaction */ 1796 devstat_end_transaction(&fdc->fd->device_stats, 1797 bp->b_bcount - bp->b_resid, 1798 DEVSTAT_TAG_NONE, 1799 (bp->b_flags & B_READ) ? DEVSTAT_READ : 1800 DEVSTAT_WRITE); 1801 fdc->fd->skip = 0; 1802 biodone(bp); 1803 fdc->state = FINDWORK; 1804 fdc->flags |= FDC_NEEDS_RESET; 1805 fdc->fd = (fd_p) 0; 1806 fdc->fdu = -1; 1807 return(1); 1808 } 1809 fdc->retry++; 1810 return(1); 1811 } 1812 1813 static int 1814 fdformat(dev, finfo, p) 1815 dev_t dev; 1816 struct fd_formb *finfo; 1817 struct proc *p; 1818 { 1819 fdu_t fdu; 1820 fd_p fd; 1821 1822 struct buf *bp; 1823 int rv = 0, s; 1824 size_t fdblk; 1825 1826 fdu = FDUNIT(minor(dev)); 1827 fd = &fd_data[fdu]; 1828 fdblk = 128 << fd->ft->secsize; 1829 1830 /* set up a buffer header for fdstrategy() */ 1831 bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); 1832 if(bp == 0) 1833 return ENOBUFS; 1834 /* 1835 * keep the process from being swapped 1836 */ 1837 p->p_flag |= P_PHYSIO; 1838 bzero((void *)bp, sizeof(struct buf)); 1839 bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; 1840 bp->b_proc = p; 1841 1842 /* 1843 * calculate a fake blkno, so fdstrategy() would initiate a 1844 * seek to the requested cylinder 1845 */ 1846 bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) 1847 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; 1848 1849 bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; 1850 bp->b_data = (caddr_t)finfo; 1851 1852 /* now do the format */ 1853 bp->b_dev = dev; 1854 fdstrategy(bp); 1855 1856 /* ...and wait for it to complete */ 1857 s = splbio(); 1858 while(!(bp->b_flags & B_DONE)) 1859 { 1860 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); 1861 if(rv == EWOULDBLOCK) 1862 break; 1863 } 1864 splx(s); 1865 1866 if(rv == EWOULDBLOCK) { 1867 /* timed out */ 1868 rv = EIO; 1869 biodone(bp); 1870 } 1871 if(bp->b_flags & B_ERROR) 1872 rv = bp->b_error; 1873 /* 1874 * allow the process to be swapped 1875 */ 1876 p->p_flag &= ~P_PHYSIO; 1877 free(bp, M_TEMP); 1878 return rv; 1879 } 1880 1881 /* 1882 * TODO: don't allocate buffer on stack. 1883 */ 1884 1885 static int 1886 fdioctl(dev, cmd, addr, flag, p) 1887 dev_t dev; 1888 u_long cmd; 1889 caddr_t addr; 1890 int flag; 1891 struct proc *p; 1892 { 1893 fdu_t fdu = FDUNIT(minor(dev)); 1894 fd_p fd = &fd_data[fdu]; 1895 size_t fdblk; 1896 1897 struct fd_type *fdt; 1898 struct disklabel *dl; 1899 char buffer[DEV_BSIZE]; 1900 int error = 0; 1901 1902 #if NFT > 0 1903 int type = FDTYPE(minor(dev)); 1904 1905 /* check for a tape ioctl */ 1906 if (type & F_TAPE_TYPE) 1907 return ftioctl(dev, cmd, addr, flag, p); 1908 #endif 1909 1910 fdblk = 128 << fd->ft->secsize; 1911 1912 switch (cmd) 1913 { 1914 case DIOCGDINFO: 1915 bzero(buffer, sizeof (buffer)); 1916 dl = (struct disklabel *)buffer; 1917 dl->d_secsize = fdblk; 1918 fdt = fd_data[FDUNIT(minor(dev))].ft; 1919 dl->d_secpercyl = fdt->size / fdt->tracks; 1920 dl->d_type = DTYPE_FLOPPY; 1921 1922 if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl) 1923 == NULL) 1924 error = 0; 1925 else 1926 error = EINVAL; 1927 1928 *(struct disklabel *)addr = *dl; 1929 break; 1930 1931 case DIOCSDINFO: 1932 if ((flag & FWRITE) == 0) 1933 error = EBADF; 1934 break; 1935 1936 case DIOCWLABEL: 1937 if ((flag & FWRITE) == 0) 1938 error = EBADF; 1939 break; 1940 1941 case DIOCWDINFO: 1942 if ((flag & FWRITE) == 0) 1943 { 1944 error = EBADF; 1945 break; 1946 } 1947 1948 dl = (struct disklabel *)addr; 1949 1950 if ((error = setdisklabel((struct disklabel *)buffer, dl, 1951 (u_long)0)) != 0) 1952 break; 1953 1954 error = writedisklabel(dev, fdstrategy, 1955 (struct disklabel *)buffer); 1956 break; 1957 case FD_FORM: 1958 if((flag & FWRITE) == 0) 1959 error = EBADF; /* must be opened for writing */ 1960 else if(((struct fd_formb *)addr)->format_version != 1961 FD_FORMAT_VERSION) 1962 error = EINVAL; /* wrong version of formatting prog */ 1963 else 1964 error = fdformat(dev, (struct fd_formb *)addr, p); 1965 break; 1966 1967 case FD_GTYPE: /* get drive type */ 1968 *(struct fd_type *)addr = *fd->ft; 1969 break; 1970 1971 case FD_STYPE: /* set drive type */ 1972 /* this is considered harmful; only allow for superuser */ 1973 if(suser(p->p_ucred, &p->p_acflag) != 0) 1974 return EPERM; 1975 *fd->ft = *(struct fd_type *)addr; 1976 break; 1977 1978 case FD_GOPTS: /* get drive options */ 1979 *(int *)addr = fd->options; 1980 break; 1981 1982 case FD_SOPTS: /* set drive options */ 1983 fd->options = *(int *)addr; 1984 break; 1985 1986 default: 1987 error = ENOTTY; 1988 break; 1989 } 1990 return (error); 1991 } 1992 1993 1994 static fd_devsw_installed = 0; 1995 1996 static void fd_drvinit(void *notused ) 1997 { 1998 1999 if( ! fd_devsw_installed ) { 2000 cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_cdevsw); 2001 fd_devsw_installed = 1; 2002 } 2003 } 2004 2005 SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) 2006 2007 2008 #endif 2009 2010 /* 2011 * Hello emacs, these are the 2012 * Local Variables: 2013 * c-indent-level: 8 2014 * c-continued-statement-offset: 8 2015 * c-continued-brace-offset: 0 2016 * c-brace-offset: -8 2017 * c-brace-imaginary-offset: 0 2018 * c-argdecl-indent: 8 2019 * c-label-offset: -8 2020 * c++-hanging-braces: 1 2021 * c++-access-specifier-offset: -8 2022 * c++-empty-arglist-indent: 8 2023 * c++-friend-offset: 0 2024 * End: 2025 */ 2026