home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / i386 / isa / fd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-25  |  15.5 KB  |  648 lines

  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.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  *    @(#)fd.c    7.4 (Berkeley) 5/25/91
  37.  */
  38.  
  39. #include "fd.h"
  40. #if NFD > 0
  41.  
  42. #include "param.h"
  43. #include "dkbad.h"
  44. #include "systm.h"
  45. #include "conf.h"
  46. #include "file.h"
  47. #include "ioctl.h"
  48. #include "buf.h"
  49. #include "uio.h"
  50. #include "i386/isa/isa_device.h"
  51. #include "i386/isa/fdreg.h"
  52. #include "i386/isa/icu.h"
  53.  
  54. #define    FDUNIT(s)    ((s)&1)
  55. #define    FDTYPE(s)    (((s)>>1)&7)
  56.  
  57. #define b_cylin b_resid
  58. #define b_step b_resid
  59. #define FDBLK 512
  60. #define NUMTYPES 4
  61.  
  62. struct fd_type {
  63.     int    sectrac;        /* sectors per track         */
  64.     int    secsize;        /* size code for sectors     */
  65.     int    datalen;        /* data len when secsize = 0 */
  66.     int    gap;            /* gap len between sectors   */
  67.     int    tracks;            /* total num of tracks       */
  68.     int    size;            /* size of disk in sectors   */
  69.     int    steptrac;        /* steps per cylinder        */
  70.     int    trans;            /* transfer speed code       */
  71. };
  72.  
  73. struct fd_type fd_types[NUMTYPES] = {
  74.      { 18,2,0xFF,0x1B,80,2880,1,0 },    /* 1.44 meg HD 3.5in floppy    */
  75.     { 15,2,0xFF,0x1B,80,2400,1,0 },    /* 1.2 meg HD floppy           */
  76.     { 9,2,0xFF,0x23,40,720,2,1 },    /* 360k floppy in 1.2meg drive */
  77.     { 9,2,0xFF,0x2A,40,720,1,1 },    /* 360k floppy in DD drive     */
  78. };
  79.  
  80. struct fd_u {
  81.     int type;        /* Drive type (HD, DD     */
  82.     int active;        /* Drive activity boolean */
  83.     int motor;        /* Motor on flag          */
  84.     struct buf head;    /* Head of buf chain      */
  85.     struct buf rhead;    /* Raw head of buf chain  */
  86.     int reset;
  87. } fd_unit[NFD];
  88.  
  89.  
  90. extern int hz;
  91.  
  92. /* state needed for current transfer */
  93. static fdc;    /* floppy disk controller io base register */
  94. int    fd_dmachan = 2;
  95. static int fd_skip;
  96. static int fd_state;
  97. static int fd_retry;
  98. static int fd_drive;
  99. static int fd_track = -1;
  100. static int fd_status[7];
  101.  
  102. /*
  103.     make sure bounce buffer for DMA is aligned since the DMA chip
  104.     doesn't roll over properly over a 64k boundary
  105. */
  106. extern struct buf *dma_bounce[];
  107.  
  108. /****************************************************************************/
  109. /*                      autoconfiguration stuff                             */
  110. /****************************************************************************/
  111. int fdprobe(), fdattach(), fd_turnoff();
  112.  
  113. struct    isa_driver fddriver = {
  114.     fdprobe, fdattach, "fd",
  115. };
  116.  
  117. fdprobe(dev)
  118. struct isa_device *dev;
  119. {
  120.     return 1;
  121. }
  122.  
  123. fdattach(dev)
  124. struct isa_device *dev;
  125. {    int    s;
  126.  
  127.     fdc = dev->id_iobase;
  128.     /* Set transfer to 500kbps */
  129.     outb(fdc+fdctl,0);
  130.     fd_turnoff(0);
  131. }
  132.  
  133. int
  134. fdsize(dev)
  135. dev_t    dev;
  136. {
  137.     return(2400);
  138. }
  139.  
  140. /****************************************************************************/
  141. /*                               fdstrategy                                 */
  142. /****************************************************************************/
  143. fdstrategy(bp)
  144.     register struct buf *bp;    /* IO operation to perform */
  145. {
  146.     register struct buf *dp,*dp0,*dp1;
  147.     long nblocks,blknum;
  148.      int    unit, type, s;
  149.  
  150.      unit = FDUNIT(minor(bp->b_dev));
  151.      type = FDTYPE(minor(bp->b_dev));
  152.  
  153. #ifdef FDTEST
  154. printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|",
  155.     unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr);
  156. #endif
  157.     if ((unit >= NFD) || (bp->b_blkno < 0)) {
  158.         printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
  159.             unit, bp->b_blkno, bp->b_bcount);
  160.         pg("fd:error in fdstrategy");
  161.         bp->b_error = EINVAL;
  162.         bp->b_flags |= B_ERROR;
  163.         goto bad;
  164.     }
  165.     /*
  166.      * Set up block calculations.
  167.      */
  168.     blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
  169.      nblocks = fd_types[type].size;
  170.     if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
  171.         if (blknum == nblocks) {
  172.             bp->b_resid = bp->b_bcount;
  173.         } else {
  174.             bp->b_error = ENOSPC;
  175.             bp->b_flags |= B_ERROR;
  176.         }
  177.         goto bad;
  178.     }
  179.      bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
  180.     dp = &fd_unit[unit].head;
  181.     dp0 = &fd_unit[0].head;
  182.     dp1 = &fd_unit[1].head;
  183.     dp->b_step = (fd_types[fd_unit[unit].type].steptrac);
  184.     s = splbio();
  185.     disksort(dp, bp);
  186.     if ((dp0->b_active == 0)&&(dp1->b_active == 0)) {
  187. #ifdef FDDEBUG
  188. printf("T|");
  189. #endif
  190.         dp->b_active = 1;
  191.         fd_drive = unit;
  192.         fd_track = -1;  /* force seek on first xfer */
  193.         untimeout(fd_turnoff,unit);
  194.         fdstart(unit);        /* start drive if idle */
  195.     }
  196.     splx(s);
  197.     return;
  198.  
  199. bad:
  200.     biodone(bp);
  201. }
  202.  
  203. /****************************************************************************/
  204. /*                            motor control stuff                           */
  205. /****************************************************************************/
  206. set_motor(unit,reset)
  207. int unit,reset;
  208. {
  209.     int m0,m1;
  210.     m0 = fd_unit[0].motor;
  211.     m1 = fd_unit[1].motor;
  212.     outb(fdc+fdout,unit | (reset ? 0 : 0xC)  | (m0 ? 16 : 0) | (m1 ? 32 : 0));
  213. }
  214.  
  215. fd_turnoff(unit)
  216. int unit;
  217. {
  218.     fd_unit[unit].motor = 0;
  219.     if (unit) set_motor(0,0);
  220.     else set_motor(1,0);
  221. }
  222.  
  223. fd_turnon(unit)
  224. int unit;
  225. {
  226.     fd_unit[unit].motor = 1;
  227.     set_motor(unit,0);
  228. }
  229.  
  230. /****************************************************************************/
  231. /*                             fdc in/out                                   */
  232. /****************************************************************************/
  233. int
  234. in_fdc()
  235. {
  236.     int i;
  237.     while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM))
  238.         if (i == NE7_RQM) return -1;
  239.     return inb(fdc+fddata);
  240. }
  241.  
  242. dump_stat()
  243. {
  244.     int i;
  245.     for(i=0;i<7;i++) {
  246.         fd_status[i] = in_fdc();
  247.         if (fd_status[i] < 0) break;
  248.     }
  249. printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n",
  250.     fd_status[0], fd_status[1], fd_status[2], fd_status[3],
  251.     fd_status[4], fd_status[5], fd_status[6] );
  252. }
  253.  
  254. out_fdc(x)
  255. int x;
  256. {
  257.     int r,errcnt;
  258.     static int maxcnt = 0;
  259.     errcnt = 0;
  260.     do {
  261.         r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM));
  262.         if (r== NE7_RQM) break;
  263.         if (r==(NE7_DIO|NE7_RQM)) {
  264.             dump_stat(); /* error: direction. eat up output */
  265. #ifdef FDOTHER
  266. printf("%lx\n",x);
  267. #endif
  268.         }
  269.         /* printf("Error r = %d:",r); */
  270.         errcnt++;
  271.     } while (1);
  272.     if (errcnt > maxcnt) {
  273.         maxcnt = errcnt;
  274. #ifdef FDOTHER
  275. printf("New MAX = %d\n",maxcnt);
  276. #endif
  277.     }
  278.     outb(fdc+fddata,x);
  279. }
  280.  
  281. /* see if fdc responding */
  282. int
  283. check_fdc()
  284. {
  285.     int i;
  286.     for(i=0;i<100;i++) {
  287.         if (inb(fdc+fdsts)& NE7_RQM) return 0;
  288.     }
  289.     return 1;
  290. }
  291.  
  292. /****************************************************************************/
  293. /*                           fdopen/fdclose                                 */
  294. /****************************************************************************/
  295. Fdopen(dev, flags)
  296.     dev_t    dev;
  297.     int    flags;
  298. {
  299.      int unit = FDUNIT(minor(dev));
  300.      int type = FDTYPE(minor(dev));
  301.     int s;
  302.  
  303.     /* check bounds */
  304.     if (unit >= NFD) return(ENXIO);
  305.     if (type >= NUMTYPES) return(ENXIO);
  306. /*
  307.     if (check_fdc()) return(EBUSY);
  308. */
  309.  
  310.     /* Set proper disk type, only allow one type */
  311.     return 0;
  312. }
  313.  
  314. fdclose(dev, flags)
  315.     dev_t dev;
  316. {
  317. }
  318.  
  319. /****************************************************************************/
  320. /*                            fdread/fdwrite                                */
  321. /****************************************************************************/
  322. /*
  323.  * Routines to do raw IO for a unit.
  324.  */
  325. fdread(dev, uio)            /* character read routine */
  326. dev_t dev;
  327. struct uio *uio;
  328. {
  329.      int unit = FDUNIT(minor(dev)) ;
  330.     if (unit >= NFD) return(ENXIO);
  331.     return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
  332. }
  333.  
  334. fdwrite(dev, uio)            /* character write routine */
  335. dev_t dev;
  336. struct uio *uio;
  337. {
  338.      int unit = FDUNIT(minor(dev)) ;
  339.     if (unit >= NFD) return(ENXIO);
  340.     return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
  341. }
  342.  
  343. /****************************************************************************/
  344. /*                                 fdstart                                  */
  345. /****************************************************************************/
  346. fdstart(unit)
  347. int unit;
  348. {
  349.     register struct buf *dp,*bp;
  350.     int s;
  351.  
  352. #ifdef FDTEST
  353. printf("st%d|",unit);
  354. #endif 
  355.     s = splbio();
  356.     if (!fd_unit[unit].motor) {
  357.         fd_turnon(unit);
  358.         /* Wait for 1 sec */
  359.         timeout(fdstart,unit,hz);
  360.         /*DELAY(1000000);*/
  361.     }else
  362.          {
  363.         /* make sure drive is selected as well as on */
  364.         /*set_motor(unit,0);*/
  365.  
  366.         dp = &fd_unit[unit].head;
  367.         bp = dp->b_actf;
  368.         fd_retry = 0;
  369.         if (fd_unit[unit].reset) fd_state = 1;
  370.         else {
  371.             /* DO a RESET */
  372.             fd_unit[unit].reset = 1;
  373.             fd_state = 5;
  374.         }
  375.         fd_skip = 0;
  376. #ifdef FDDEBUG
  377. printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
  378. #endif
  379.         if (bp->b_cylin != fd_track) {
  380.         /* Seek necessary, never quite sure where head is at! */
  381.         out_fdc(15);    /* Seek function */
  382.         out_fdc(unit);    /* Drive number */
  383.         out_fdc(bp->b_cylin * dp->b_step);
  384.         } else fdintr(0xff);
  385.     }
  386.     splx(s);
  387. }
  388.  
  389. fd_timeout(x)
  390. int x;
  391. {
  392.     int i,j;
  393.     struct buf *dp,*bp;
  394.  
  395.     dp = &fd_unit[fd_drive].head;
  396.     bp = dp->b_actf;
  397.  
  398.     out_fdc(0x4);
  399.     out_fdc(fd_drive);
  400.     i = in_fdc();
  401.     printf("Timeout drive status %lx\n",i);
  402.  
  403.     out_fdc(0x8);
  404.     i = in_fdc();
  405.     j = in_fdc();
  406.     printf("ST0 = %lx, PCN = %lx\n",i,j);
  407.  
  408.     if (bp) badtrans(dp,bp);
  409. }
  410.  
  411. /****************************************************************************/
  412. /*                                 fdintr                                   */
  413. /****************************************************************************/
  414. fdintr(unit)
  415. {
  416.     register struct buf *dp,*bp;
  417.     struct buf *dpother;
  418.     int read,head,trac,sec,i,s,sectrac,cyl;
  419.     unsigned long blknum;
  420.     struct fd_type *ft;
  421.  
  422. #ifdef FDTEST
  423.     printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive);
  424. #endif
  425.  
  426.     dp = &fd_unit[fd_drive].head;
  427.     bp = dp->b_actf;
  428.     read = bp->b_flags & B_READ;
  429.      ft = &fd_types[FDTYPE(bp->b_dev)];
  430.  
  431.     switch (fd_state) {
  432.     case 1 : /* SEEK DONE, START DMA */
  433.         /* Make sure seek really happened*/
  434.         if (unit != 0xff) {
  435.             out_fdc(0x8);
  436.             i = in_fdc();
  437.             cyl = in_fdc();
  438.             if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
  439. printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl);
  440.                 return;
  441.             }
  442.         }
  443.  
  444.         fd_track = bp->b_cylin;
  445.         at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
  446.         blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
  447.             + fd_skip/FDBLK;
  448.         sectrac = ft->sectrac;
  449.         sec = blknum %  (sectrac * 2);
  450.         head = sec / sectrac;
  451.         sec = sec % sectrac + 1;
  452.  
  453.         if (read)  out_fdc(0xE6);    /* READ */
  454.         else out_fdc(0xC5);        /* WRITE */
  455.         out_fdc(head << 2 | fd_drive);    /* head & unit */
  456.         out_fdc(fd_track);        /* track */
  457.         out_fdc(head);
  458.         out_fdc(sec);            /* sector XXX +1? */
  459.         out_fdc(ft->secsize);        /* sector size */
  460.         out_fdc(sectrac);        /* sectors/track */
  461.         out_fdc(ft->gap);        /* gap size */
  462.         out_fdc(ft->datalen);        /* data length */
  463.         fd_state = 2;
  464.         /* XXX PARANOIA */
  465.         untimeout(fd_timeout,2);
  466.         timeout(fd_timeout,2,hz);
  467.         break;
  468.     case 2 : /* IO DONE, post-analyze */
  469.         untimeout(fd_timeout,2);
  470.         for(i=0;i<7;i++) {
  471.             fd_status[i] = in_fdc();
  472.         }
  473.         if (fd_status[0]&0xF8) {
  474. #ifdef FDOTHER
  475. printf("status0 err %d:",fd_status[0]);
  476. #endif
  477.             goto retry;
  478.         }
  479. /*
  480.         if (fd_status[1]){
  481.             printf("status1 err %d:",fd_status[0]);
  482.             goto retry;
  483.         }
  484.         if (fd_status[2]){
  485.             printf("status2 err %d:",fd_status[0]);
  486.             goto retry;
  487.         }
  488. */
  489.         /* All OK */
  490.         if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
  491.             /* RAW transfer */
  492.             if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
  493.                 bp->b_un.b_addr+fd_skip, FDBLK);
  494.         }
  495.         fd_skip += FDBLK;
  496.         if (fd_skip >= bp->b_bcount) {
  497. #ifdef FDTEST
  498. printf("DONE %d|", bp->b_blkno);
  499. #endif
  500.             /* ALL DONE */
  501.             fd_skip = 0;
  502.             bp->b_resid = 0;
  503.             dp->b_actf = bp->av_forw;
  504.             biodone(bp);
  505.             nextstate(dp);
  506.  
  507.         } else {
  508. #ifdef FDDEBUG
  509. printf("next|");
  510. #endif
  511.             /* set up next transfer */
  512.             blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
  513.                 + fd_skip/FDBLK;
  514.             fd_state = 1;
  515.             bp->b_cylin = (blknum / (ft->sectrac * 2));
  516.             if (bp->b_cylin != fd_track) {
  517. #ifdef FDTEST
  518. printf("Seek|");
  519. #endif
  520.                 /* SEEK Necessary */
  521.                 out_fdc(15);    /* Seek function */
  522.                 out_fdc(fd_drive);/* Drive number */
  523.                 out_fdc(bp->b_cylin * dp->b_step);
  524.                 break;
  525.             } else fdintr(0xff);
  526.         }
  527.         break;
  528.     case 3:
  529. #ifdef FDOTHER
  530. printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
  531. #endif
  532.         /* Seek necessary */
  533.         out_fdc(15);    /* Seek function */
  534.         out_fdc(fd_drive);/* Drive number */
  535.         out_fdc(bp->b_cylin * dp->b_step);
  536.         fd_state = 1;
  537.         break;
  538.     case 4:
  539.         out_fdc(3); /* specify command */
  540.         out_fdc(0xDF);
  541.         out_fdc(2);
  542.         out_fdc(7);    /* Recalibrate Function */
  543.         out_fdc(fd_drive);
  544.         fd_state = 3;
  545.         break;
  546.     case 5:
  547. #ifdef FDOTHER
  548.         printf("**RESET**\n");
  549. #endif
  550.         /* Try a reset, keep motor on */
  551.         set_motor(fd_drive,1);
  552.         set_motor(fd_drive,0);
  553.         outb(fdc+fdctl,ft->trans);
  554.         fd_retry++;
  555.         fd_state = 4;
  556.         break;
  557.     default:
  558.         printf("Unexpected FD int->");
  559.         out_fdc(0x8);
  560.         i = in_fdc();
  561.         sec = in_fdc();
  562.         printf("ST0 = %lx, PCN = %lx\n",i,sec);
  563.         out_fdc(0x4A); 
  564.         out_fdc(fd_drive);
  565.         for(i=0;i<7;i++) {
  566.             fd_status[i] = in_fdc();
  567.         }
  568.     printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
  569.         fd_status[0], fd_status[1], fd_status[2], fd_status[3],
  570.         fd_status[4], fd_status[5], fd_status[6] );
  571.         break;
  572.     }
  573.     return;
  574. retry:
  575.     switch(fd_retry) {
  576.     case 0: case 1:
  577.     case 2: case 3:
  578.         break;
  579.     case 4:
  580.         fd_retry++;
  581.         fd_state = 5;
  582.         fdintr(0xff);
  583.         return;
  584.     case 5: case 6: case 7:
  585.         break;
  586.     default:
  587.         printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
  588.         fd_status[0], fd_status[1], fd_status[2], fd_status[3],
  589.         fd_status[4], fd_status[5], fd_status[6] );
  590.         badtrans(dp,bp);
  591.         return;
  592.     }
  593.     fd_state = 1;
  594.     fd_retry++;
  595.     fdintr(0xff);
  596. }
  597.  
  598. badtrans(dp,bp)
  599. struct buf *dp,*bp;
  600. {
  601.  
  602.     bp->b_flags |= B_ERROR;
  603.     bp->b_error = EIO;
  604.     bp->b_resid = bp->b_bcount - fd_skip;
  605.     dp->b_actf = bp->av_forw;
  606.     fd_skip = 0;
  607.     biodone(bp);
  608.     nextstate(dp);
  609.  
  610. }
  611.  
  612. /*
  613.     nextstate : After a transfer is done, continue processing
  614.     requests on the current drive queue.  If empty, go to
  615.     the other drives queue.  If that is empty too, timeout
  616.     to turn off the current drive in 5 seconds, and go
  617.     to state 0 (not expecting any interrupts).
  618. */
  619.  
  620. nextstate(dp)
  621. struct buf *dp;
  622. {
  623.     struct buf *dpother;
  624.     
  625.     dpother = &fd_unit[fd_drive ? 0 : 1].head;
  626.     if (dp->b_actf) fdstart(fd_drive);
  627.     else if (dpother->b_actf) {
  628. #ifdef FDTEST
  629. printf("switch|");
  630. #endif
  631.         untimeout(fd_turnoff,fd_drive);
  632.         timeout(fd_turnoff,fd_drive,5*hz);
  633.         fd_drive = 1 - fd_drive;
  634.         dp->b_active = 0;
  635.         dpother->b_active = 1;
  636.         fdstart(fd_drive);
  637.     } else {
  638. #ifdef FDTEST
  639. printf("off|");
  640. #endif
  641.         untimeout(fd_turnoff,fd_drive);
  642.         timeout(fd_turnoff,fd_drive,5*hz);
  643.         fd_state = 0;
  644.         dp->b_active = 0;
  645.     }
  646. }
  647. #endif
  648.