nec765Fd.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:32k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* nec765Fd.c - NEC 765 floppy disk device driver */
  2. /* Copyright 1989-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01i,01aug01,jkf  doubled sync semaphore timeout per T3 SPR#63543.
  8. 01o,11jun01,jyo  SPR#65990, write protected media handling.
  9. 01i,24feb98,hdn  added support for disk-change in fdStatusChk().
  10. 01h,30aug95,hdn  added support for write-protected, unformatted, no-disk.
  11. 01g,14jun95,hdn  removed function declarations defined in sysLib.h.
  12. 01f,24jan95,jdi  doc cleanup.
  13. 01e,25oct94,hdn  added fdRawio() to provide physical IO.
  14.  swapped 1st and 2nd parameter of fdDevCreate().
  15. 01d,03jun94,hdn  changed DESCRIPTION, 386 to 386/486.
  16.  added an explanation of parameters for fdDevCreate().
  17. 01c,22apr94,hdn  made two imported globals sysFdBuf, sysFdBufSize.
  18. 01b,04nov93,hdn  cleaned up.
  19. 01a,21sep93,hdn  written.
  20. */
  21. /*
  22. DESCRIPTION
  23. This is the driver for the NEC 765 Floppy Chip used on the PC 386/486.
  24. USER-CALLABLE ROUTINES
  25. Most of the routines in this driver are accessible only through the I/O
  26. system.  However, two routines must be called directly:  fdDrv() to
  27. initialize the driver, and fdDevCreate() to create devices.
  28. Before the driver can be used, it must be initialized by calling fdDrv().
  29. This routine should be called exactly once, before any reads, writes, or
  30. calls to fdDevCreate().  Normally, it is called from usrRoot() in
  31. usrConfig.c.
  32. The routine fdRawio() allows physical I/O access.  Its first argument is a
  33. drive number, 0 to 3; the second argument is a type of diskette; the third
  34. argument is a pointer to the FD_RAW structure, which is defined in nec765Fd.h.
  35. Interleaving is not supported when the driver formats.
  36. Two types of diskettes are currently supported:
  37. 3.5" 2HD 1.44MB and 5.25" 2HD 1.2MB.  You can add additional diskette
  38. types to the `fdTypes[]' table in sysLib.c.
  39. The BLK_DEV bd_mode field will reflect the disk's write protect tab.
  40. INTERNAL
  41. The driver uses memory area at sysFdBuf(FD_DMA_BUF) size of sysFdBufSize
  42. (FD_DMA_BUF_SIZE) for DMA. Reasons are First of all, the DMA chip 
  43. understand only 24 bits address. Secondly, a buffer should be in one page,
  44. the other word a buffer can not cross the 64k byte boundary. 
  45. SEE ALSO:
  46. .pG "I/O System"
  47. */
  48. #include "vxWorks.h"
  49. #include "taskLib.h"
  50. #include "blkIo.h"
  51. #include "ioLib.h"
  52. #include "iosLib.h"
  53. #include "memLib.h"
  54. #include "stdlib.h"
  55. #include "errnoLib.h"
  56. #include "stdio.h"
  57. #include "string.h"
  58. #include "private/semLibP.h"
  59. #include "intLib.h"
  60. #include "iv.h"
  61. #include "wdLib.h"
  62. #include "sysLib.h"
  63. #include "sys/fcntlcom.h"
  64. #include "drv/fdisk/nec765Fd.h"
  65. IMPORT int dmaSetup (int direction, void *pAddr, UINT nbytes, UINT chan);
  66. IMPORT FD_TYPE fdTypes[];
  67. IMPORT UINT sysFdBuf;
  68. IMPORT UINT sysFdBufSize;
  69. /* global */
  70. int  fdIntCount = 0; /* interrupt count */
  71. int  fdRetry = 2; /* max retry count */
  72. int  fdTimeout = 10000; /* max timeout count */
  73. int  fdSemSec = 2; /* semaphore timeout seconds */
  74. int  fdWdSec = 4; /* watchdog timeout seconds */
  75. SEMAPHORE  fdSyncSem; /* binary semaphore for syncronization */
  76. SEMAPHORE  fdMuteSem; /* mutex  semaphore for mutual-exclusion */
  77. WDOG_ID  fdWid; /* watchdog to turn motor off */
  78. /* local */
  79. LOCAL char fdDORvalues[] = {0x1c, 0x2d, 0x4e, 0x8f};
  80. LOCAL char fdAccess[] = {0,0,0,0}; /* flag indicate first access */
  81. LOCAL BOOL fdDrvInstalled = FALSE; /* TRUE = facility installed */
  82. LOCAL int  fdCylinder = 1; /* last cylinder read/written */
  83. /* function prototypes */
  84. LOCAL STATUS fdBlkRd (FD_DEV *pFdDev, int startBlk, int nBlks, char *pBuf);
  85. LOCAL STATUS fdBlkWrt (FD_DEV *pFdDev, int startBlk, int nBlks, char *pBuf);
  86. LOCAL STATUS fdIoctl (FD_DEV *pFdDev, int function, int arg);
  87. LOCAL STATUS fdReset (FD_DEV *pFdDev);
  88. LOCAL STATUS fdStatusChk(FD_DEV *pFdDev);
  89. LOCAL STATUS fdBlkRW    (FD_DEV *pFdDev, int startBlk, int nBlks, char *pBuf,
  90.  int direction);
  91. LOCAL void   fdIntr         (int ctrl);
  92. LOCAL STATUS fdCmdSend      (UCHAR *pCommand, int nBytes);
  93. LOCAL STATUS fdResultPhase  (UCHAR *pResults, BOOL immediate, int nBytes);
  94. LOCAL STATUS fdIntSense     (int seekEnd);
  95. LOCAL void   fdInit     (void);
  96. LOCAL void   fdDriveRelease (void);
  97. LOCAL void   fdDriveSelect  (int fdType, int drive);
  98. LOCAL STATUS fdRecalib      (int drive);
  99. LOCAL STATUS fdSeek         (int drive, int cylinder, int head);
  100. LOCAL STATUS fdRW           (int fdType, int drive, int cylinder, int head,
  101.      int sector, void *pBuf, int nSecs, int direction);
  102. LOCAL STATUS fdFormat       (int fdType, int drive, int cylinder, int head,
  103.           int interleave);
  104. LOCAL int    fdDriveIsWP    (int drive);
  105. /*******************************************************************************
  106. *
  107. * fdDrv - initialize the floppy disk driver
  108. *
  109. * This routine initializes the floppy driver, sets up interrupt vectors,
  110. * and performs hardware initialization of the floppy chip.
  111. *
  112. * This routine should be called exactly once, before any reads, writes,
  113. * or calls to fdDevCreate().  Normally, it is called by usrRoot()
  114. * in usrConfig.c.
  115. *
  116. * RETURNS: OK.
  117. *
  118. * SEE ALSO: fdDevCreate(), fdRawio()
  119. */
  120. STATUS fdDrv
  121.     (
  122.     int vector, /* interrupt vector */
  123.     int level /* interrupt level */
  124.     )
  125.     {
  126.     if (!fdDrvInstalled)
  127. {
  128.         semBInit (&fdSyncSem, SEM_Q_FIFO, SEM_EMPTY);
  129.         semMInit (&fdMuteSem, SEM_Q_PRIORITY | SEM_DELETE_SAFE |
  130.   SEM_INVERSION_SAFE);
  131.         (void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (vector),
  132.            (VOIDFUNCPTR)fdIntr, 0);
  133.         sysIntEnablePIC (level); /* unmask the interrupt level */
  134.         fdWid = wdCreate ();
  135.         fdInit ();
  136. fdDrvInstalled = TRUE;
  137. }
  138.     return (OK);
  139.     }
  140. /*******************************************************************************
  141. *
  142. * fdDevCreate - create a device for a floppy disk
  143. *
  144. * This routine creates a device for a specified floppy disk.
  145. *
  146. * The <drive> parameter is the drive number of the floppy disk;
  147. * valid values are 0 to 3.
  148. *
  149. * The <fdType> parameter specifies the type of diskette, which is described
  150. * in the structure table `fdTypes[]' in sysLib.c.  <fdType> is an index to
  151. * the table.  Currently the table contains two diskette types:
  152. * .iP "" 4
  153. * An <fdType> of 0 indicates the first entry in the table (3.5" 2HD, 1.44MB);
  154. * .iP
  155. * An <fdType> of 1 indicates the second entry in the table (5.25" 2HD, 1.2MB).
  156. * .LP
  157. * Members of the `fdTypes[]' structure are:
  158. * .CS
  159. *     int  sectors;       /@ no of sectors @/
  160. *     int  sectorsTrack;  /@ sectors per track @/
  161. *     int  heads;         /@ no of heads @/
  162. *     int  cylinders;     /@ no of cylinders @/
  163. *     int  secSize;       /@ bytes per sector, 128 << secSize @/
  164. *     char gap1;          /@ gap1 size for read, write @/
  165. *     char gap2;          /@ gap2 size for format @/
  166. *     char dataRate;      /@ data transfer rate @/
  167. *     char stepRate;      /@ stepping rate @/
  168. *     char headUnload;    /@ head unload time @/
  169. *     char headLoad;      /@ head load time @/
  170. *     char mfm;           /@ MFM bit for read, write, format @/
  171. *     char sk;            /@ SK bit for read @/
  172. *     char *name;         /@ name @/
  173. * .CE
  174. *
  175. * The <nBlocks> parameter specifies the size of the device, in blocks.
  176. * If <nBlocks> is zero, the whole disk is used.
  177. *
  178. * The <blkOffset> parameter specifies an offset, in blocks, from the start
  179. * of the device to be used when writing or reading the floppy disk.  This
  180. * offset is added to the block numbers passed by the file system during
  181. * disk accesses.  (VxWorks file systems always use block numbers beginning
  182. * at zero for the start of a device.)  Normally, <blkOffset> is 0.
  183. *
  184. *
  185. * RETURNS:
  186. * A pointer to a block device structure (BLK_DEV) or NULL if memory cannot
  187. * be allocated for the device structure.
  188. *
  189. * SEE ALSO: fdDrv(), fdRawio(), dosFsMkfs(), dosFsDevInit(), rt11FsDevInit(),
  190. * rt11FsMkfs(), rawFsDevInit()
  191. */
  192. BLK_DEV *fdDevCreate
  193.     (
  194.     int drive, /* driver number of floppy disk (0 - 3) */
  195.     int fdType, /* type of floppy disk */
  196.     int nBlocks, /* device size in blocks (0 = whole disk) */
  197.     int blkOffset /* offset from start of device */
  198.     )
  199.     {
  200.     FD_DEV *pFdDev;
  201.     BLK_DEV *pBlkDev;
  202.     FD_TYPE *pType = &fdTypes[fdType];
  203.     if (!fdDrvInstalled)
  204. return (NULL);
  205.     if (nBlocks == 0)
  206. nBlocks = pType->sectors;
  207.     if ((UINT)drive >= FD_MAX_DRIVES)
  208. return (NULL);
  209.     if ((pFdDev = (FD_DEV *)calloc(sizeof (FD_DEV), 1)) == NULL)
  210. return (NULL);
  211.     pBlkDev = &pFdDev->blkDev;
  212.     pBlkDev->bd_nBlocks = nBlocks;
  213.     pBlkDev->bd_bytesPerBlk = 128 << pType->secSize;
  214.     pBlkDev->bd_blksPerTrack = pType->sectorsTrack;
  215.     pBlkDev->bd_nHeads = pType->heads;
  216.     pBlkDev->bd_removable = TRUE;
  217.     pBlkDev->bd_retry = 1;
  218.     pBlkDev->bd_readyChanged = TRUE;
  219.     pBlkDev->bd_blkRd = fdBlkRd;
  220.     pBlkDev->bd_blkWrt = fdBlkWrt;
  221.     pBlkDev->bd_ioctl = fdIoctl;
  222.     pBlkDev->bd_reset = fdReset;
  223.     pBlkDev->bd_statusChk = fdStatusChk;
  224.     pFdDev->fdType = fdType;
  225.     pFdDev->drive = drive;
  226.     pFdDev->blkOffset = blkOffset;
  227.     /* SPR#65990, now check for the WP setting */
  228.     /* power up the drive */
  229.     sysOutByte (FD_REG_OUTPUT, fdDORvalues[drive]); 
  230.     sysDelay ();
  231.     /* set the bd_mode per the WP tab */
  232.     pBlkDev->bd_mode = (fdDriveIsWP(drive)) ? O_RDONLY : O_RDWR;
  233.     /* power down the device */
  234.     fdDriveRelease (); 
  235.     sysDelay();
  236.     return (&pFdDev->blkDev);
  237.     }
  238. /*******************************************************************************
  239. *
  240. * fdRawio - provide raw I/O access
  241. *
  242. * This routine is called when the raw I/O access is necessary.
  243. *
  244. * The <drive> parameter is the drive number of the floppy disk;
  245. * valid values are 0 to 3.
  246. *
  247. * The <fdType> parameter specifies the type of diskette, which is described
  248. * in the structure table `fdTypes[]' in sysLib.c.  <fdType> is an index to
  249. * the table.  Currently the table contains two diskette types:
  250. * .iP "" 4
  251. * An <fdType> of 0 indicates the first entry in the table (3.5" 2HD, 1.44MB);
  252. * .iP
  253. * An <fdType> of 1 indicates the second entry in the table (5.25" 2HD, 1.2MB).
  254. * .LP
  255. *
  256. * The <pFdRaw> is a pointer to the structure FD_RAW, defined in nec765Fd.h
  257. *
  258. * RETURNS:  OK or ERROR.
  259. *
  260. * SEE ALSO: fdDrv(), fdDevCreate()
  261. */
  262. STATUS fdRawio
  263.     (
  264.     int drive, /* drive number of floppy disk (0 - 3) */
  265.     int fdType, /* type of floppy disk */
  266.     FD_RAW *pFdRaw /* pointer to FD_RAW structure */
  267.     )
  268.     {
  269.     FD_DEV fdDev;
  270.     BLK_DEV *pBlkDev = &fdDev.blkDev;
  271.     FD_TYPE *pType = &fdTypes[fdType];
  272.     UINT startBlk;
  273.     if (!fdDrvInstalled)
  274. return (ERROR);
  275.     if ((UINT)drive >= FD_MAX_DRIVES)
  276. return (ERROR);
  277.     if ((pFdRaw->cylinder >= pType->cylinders) ||
  278.         (pFdRaw->head >= pType->heads) ||
  279.         (pFdRaw->sector >  pType->sectorsTrack) ||
  280.         (pFdRaw->sector == 0))
  281. return (ERROR);
  282.     pBlkDev->bd_nBlocks = pType->sectors;
  283.     pBlkDev->bd_bytesPerBlk = 128 << pType->secSize;
  284.     pBlkDev->bd_blksPerTrack = pType->sectorsTrack;
  285.     pBlkDev->bd_nHeads = pType->heads;
  286.     pBlkDev->bd_removable = TRUE;
  287.     pBlkDev->bd_retry = 1;
  288.     pBlkDev->bd_readyChanged = TRUE;
  289.     pBlkDev->bd_blkRd = fdBlkRd;
  290.     pBlkDev->bd_blkWrt = fdBlkWrt;
  291.     pBlkDev->bd_ioctl = fdIoctl;
  292.     pBlkDev->bd_reset = fdReset;
  293.     pBlkDev->bd_statusChk = fdStatusChk;
  294.     fdDev.drive = drive;
  295.     fdDev.fdType = fdType;
  296.     fdDev.blkOffset = 0;
  297.     /* SPR#65990, now check for the WP setting */
  298.     /* power up the drive */
  299.     sysOutByte (FD_REG_OUTPUT, fdDORvalues[drive]); 
  300.     sysDelay ();
  301.     /* set the bd_mode per the WP tab */
  302.     pBlkDev->bd_mode = (fdDriveIsWP(drive)) ? O_RDONLY : O_RDWR;
  303.     startBlk = pFdRaw->cylinder * (pType->sectorsTrack * pType->heads) +
  304.        pFdRaw->head * pType->sectorsTrack +
  305.        pFdRaw->sector - 1;
  306.     return (fdBlkRW (&fdDev, startBlk, pFdRaw->nSecs, pFdRaw->pBuf,
  307.      pFdRaw->direction));
  308.     }
  309. /*******************************************************************************
  310. *
  311. * fdBlkRd - read one or more blocks from a floppy disk
  312. *
  313. * This routine reads one or more blocks from the specified device,
  314. * starting with the specified block number.
  315. *
  316. * If any block offset was specified during fdDevCreate(), it is added
  317. * to <startBlk> before the transfer takes place.
  318. *
  319. * RETURNS: OK, ERROR if the read command didn't succeed.
  320. */
  321. LOCAL STATUS fdBlkRd
  322.     (
  323.     FD_DEV *pFdDev,
  324.     int startBlk,
  325.     int nBlks,
  326.     char *pBuf
  327.     )
  328.     {
  329.     return (fdBlkRW (pFdDev, startBlk, nBlks, pBuf, O_RDONLY));
  330.     }
  331. /*******************************************************************************
  332. *
  333. * fdBlkWrt - write one or more blocks to a floppy disk
  334. *
  335. * This routine writes one or more blocks to the specified device,
  336. * starting with the specified block number.
  337. *
  338. * If any block offset was specified during fdDevCreate(), it is added
  339. * to <startBlk> before the transfer takes place.
  340. *
  341. * RETURNS: OK, ERROR if the write command didn't succeed.
  342. */
  343. LOCAL STATUS fdBlkWrt
  344.     (
  345.     FD_DEV *pFdDev,
  346.     int startBlk,
  347.     int nBlks,
  348.     char *pBuf
  349.     )
  350.     {
  351.     return (fdBlkRW (pFdDev, startBlk, nBlks, pBuf, O_WRONLY));
  352.     }
  353. /*******************************************************************************
  354. *
  355. * fdReset - reset a floppy disk controller
  356. *
  357. * This routine resets a floppy disk controller.
  358. *
  359. * RETURNS: OK, always.
  360. */
  361. LOCAL STATUS fdReset
  362.     (
  363.     FD_DEV *pFdDev
  364.     )
  365.     {
  366.     
  367.     fdInit ();
  368.     fdDriveSelect (pFdDev->fdType, pFdDev->drive);
  369.     (void) fdRecalib (pFdDev->drive);
  370.     fdDriveRelease ();
  371.     return (OK);
  372.     }
  373. /*******************************************************************************
  374. *
  375. * fdIoctl - do device specific control function
  376. *
  377. * This routine is called when the file system cannot handle an ioctl()
  378. * function.
  379. *
  380. * RETURNS:  OK or ERROR.
  381. */
  382. LOCAL STATUS fdIoctl
  383.     (
  384.     FD_DEV *pFdDev,
  385.     int function,
  386.     int arg
  387.     )
  388.     {
  389.     FD_TYPE *pType = &fdTypes[pFdDev->fdType];
  390.     FAST int status = ERROR;
  391.     FAST int cylinder;
  392.     FAST int head;
  393.     int retryCount;
  394.     wdCancel (fdWid);
  395.     semTake (&fdMuteSem, WAIT_FOREVER);
  396.     switch (function)
  397. {
  398. case FIODISKFORMAT:
  399.             fdDriveSelect (pFdDev->fdType, pFdDev->drive);
  400.     (void) fdRecalib (pFdDev->drive);
  401.     for (cylinder = 0; cylinder < pType->cylinders; cylinder++)
  402.         for (head = 0; head < pType->heads; head++)
  403.     {
  404.     retryCount = 0;
  405.     while (fdSeek(pFdDev->drive, cylinder, head) != OK)
  406.              if (++retryCount > fdRetry)
  407.     {
  408.          (void) errnoSet (S_ioLib_DEVICE_ERROR);
  409.     goto doneIoctl;
  410.     }
  411.     retryCount = 0;
  412.     while (fdFormat(pFdDev->fdType, pFdDev->drive, 
  413.    cylinder, head, arg) != OK)
  414.              if (++retryCount > fdRetry)
  415.     {
  416.          (void) errnoSet (S_ioLib_DEVICE_ERROR);
  417.     goto doneIoctl;
  418.     }
  419.     }
  420.     status = OK;
  421.     break;
  422. default:
  423.     (void) errnoSet (S_ioLib_UNKNOWN_REQUEST);
  424. }
  425. doneIoctl:
  426.     semGive (&fdMuteSem);
  427.     wdStart (fdWid, (sysClkRateGet() * fdWdSec), (FUNCPTR)fdDriveRelease, 0);
  428.     return (status);
  429.     }
  430. /*******************************************************************************
  431. *
  432. * fdStatusChk - check a status of a floppy disk
  433. *
  434. * This routine checks for a disk change on devices.
  435. *
  436. * RETURNS: OK.
  437. */
  438. LOCAL STATUS fdStatusChk
  439.     (
  440.     FD_DEV *pFdDev
  441.     )
  442.     {
  443.     FD_TYPE *pType = &fdTypes[pFdDev->fdType];
  444.     wdCancel (fdWid);
  445.     semTake (&fdMuteSem, WAIT_FOREVER);
  446.     sysOutByte (FD_REG_OUTPUT, fdDORvalues[pFdDev->drive]); 
  447.     sysDelay ();
  448.     /* 
  449.      * Bit 7 is set when a diskette is changed.
  450.      * To clear the bit, we need to perform a seek.  
  451.      */
  452.     if (sysInByte (FD_REG_INPUT) & 0x80)
  453. {
  454. pFdDev->blkDev.bd_readyChanged = TRUE;
  455. /* do seek to clear DCHG bit in FD_REG_INPUT */
  456. if (++fdCylinder >= pType->cylinders)
  457.     fdCylinder = 1;
  458.         fdDriveSelect (pFdDev->fdType, pFdDev->drive);
  459. (void) fdSeek(pFdDev->drive, fdCylinder, 0);
  460.         /* set the bd_mode per the WP tab */
  461.         pFdDev->blkDev.bd_mode =
  462. (fdDriveIsWP(pFdDev->drive))? O_RDONLY : O_RDWR;
  463. }
  464.     
  465.     semGive (&fdMuteSem);
  466.     wdStart (fdWid, (sysClkRateGet() * fdWdSec), 
  467. (FUNCPTR)fdDriveRelease, 0);
  468.     return (OK);
  469.     }
  470. /*******************************************************************************
  471. *
  472. * fdBlkRW - read or write sectors to a floppy disk.
  473. *
  474. * Read or write sectors to a floppy disk.
  475. *
  476. * RETURNS: OK, ERROR if the command didn't succeed.
  477. */
  478. LOCAL STATUS fdBlkRW
  479.     (
  480.     FD_DEV *pFdDev,
  481.     int startBlk,
  482.     int nBlks,
  483.     char *pBuf,
  484.     int direction
  485.     )
  486.     {
  487.     BLK_DEV *pBlkDev = &pFdDev->blkDev;
  488.     FD_TYPE *pType = &fdTypes[pFdDev->fdType];
  489.     int status = ERROR;
  490.     int rwStatus;
  491.     int head;
  492.     int cylinder;
  493.     int sector;
  494.     int ix;
  495.     int nSecs;
  496.     int retryRW0;
  497.     int retryRW1;
  498.     int retrySeek;
  499.     wdCancel (fdWid);
  500.     semTake (&fdMuteSem, WAIT_FOREVER);
  501.     startBlk += pFdDev->blkOffset;
  502.     /* recalibrate is necessary before the first access */
  503.     fdDriveSelect (pFdDev->fdType, pFdDev->drive);
  504.     if (fdAccess[pFdDev->drive] == 0)
  505. {
  506. (void) fdRecalib (pFdDev->drive);
  507.         fdAccess[pFdDev->drive] = 1;
  508. }
  509.     for (ix = 0; ix < nBlks; ix += nSecs)
  510. {
  511. cylinder = startBlk / (pType->sectorsTrack * pType->heads);
  512. sector   = startBlk % (pType->sectorsTrack * pType->heads);
  513. head     = sector / pType->sectorsTrack;
  514. sector   = sector % pType->sectorsTrack + 1;
  515. fdCylinder = cylinder; /* remember it for fdStatusChk() */
  516. retrySeek = 0;
  517. while (fdSeek(pFdDev->drive, cylinder, head) != OK)
  518.     if (++retrySeek > fdRetry)
  519. goto doneRW;
  520. nSecs = min (nBlks - ix, pType->sectorsTrack - sector + 1);
  521.         while ((pBlkDev->bd_bytesPerBlk * nSecs) > sysFdBufSize)
  522.     nSecs -= 1;
  523. retryRW1 = 0;
  524. retryRW0 = 0;
  525. while ((rwStatus = fdRW (pFdDev->fdType, pFdDev->drive, cylinder, head, 
  526.  sector, pBuf, nSecs, direction)) != OK)
  527.     {
  528.     if ((rwStatus == FD_UNFORMATED) ||
  529.      (rwStatus == FD_WRITE_PROTECTED) ||
  530.      (rwStatus == FD_DISK_NOT_PRESENT))
  531. retryRW0 = fdRetry;
  532.     if (++retryRW0 > fdRetry)
  533. {
  534.         (void) fdRecalib (pFdDev->drive);
  535.         if (++retryRW1 > fdRetry)
  536.     goto doneRW;
  537. retrySeek = 0;
  538. while (fdSeek(pFdDev->drive, cylinder, head) != OK)
  539.          if (++retrySeek > fdRetry)
  540. goto doneRW;
  541. retryRW0 = 0;
  542. }
  543.     }
  544.         startBlk += nSecs;
  545.         pBuf  += pBlkDev->bd_bytesPerBlk * nSecs;
  546. }
  547.     status = OK;
  548. doneRW:
  549.     if (rwStatus == FD_UNFORMATED)
  550.         (void)errnoSet (S_ioLib_UNFORMATED);
  551.     else if (rwStatus == FD_WRITE_PROTECTED)
  552. {
  553.         pBlkDev->bd_mode = O_RDONLY;
  554.         (void)errnoSet (S_ioLib_WRITE_PROTECTED);
  555. }
  556.     else if (rwStatus == FD_DISK_NOT_PRESENT)
  557.         (void)errnoSet (S_ioLib_DISK_NOT_PRESENT);
  558.     else if (rwStatus == ERROR)
  559.         (void)errnoSet (S_ioLib_DEVICE_ERROR);
  560.     semGive (&fdMuteSem);
  561.     wdStart (fdWid, (sysClkRateGet() * fdWdSec), (FUNCPTR)fdDriveRelease, 0);
  562.     return (status);
  563.     }
  564. /*******************************************************************************
  565. *
  566. * fdInit - init a floppy disk controller
  567. *
  568. * This routine initializes a floppy disk controller.
  569. *
  570. * RETURNS: N/A
  571. */
  572. LOCAL void fdInit (void)
  573.     {
  574.     int ix;
  575.     /* reset the chip */
  576.     sysOutByte (FD_REG_OUTPUT, (FD_DOR_RESET | FD_DOR_DMA_DISABLE));
  577.     taskDelay (sysClkRateGet() >> 1);
  578.     sysOutByte (FD_REG_OUTPUT, (FD_DOR_CLEAR_RESET | FD_DOR_DMA_ENABLE));
  579.     taskDelay (sysClkRateGet() >> 1);
  580.     
  581.     sysOutByte (FD_REG_CONFIG, 0);
  582.     if (semTake (&fdSyncSem, sysClkRateGet() * fdSemSec) != OK)
  583. return;
  584.     for (ix = 0; ix < FD_MAX_DRIVES; ix++)
  585. (void) fdIntSense (0);
  586. #ifdef FD_DEBUG
  587.     printErr ("fdInitn");
  588. #endif /* FD_DEBUG */
  589.     }
  590. /*******************************************************************************
  591. *
  592. * fdIntr - Floppy controller interrupt handler.
  593. *
  594. * RETURNS: N/A
  595. */
  596. LOCAL void fdIntr
  597.     (
  598.     int ctrl
  599.     )
  600.     {
  601.     fdIntCount++; /* XXX */
  602.     semGive (&fdSyncSem);
  603.     }
  604. /*******************************************************************************
  605. *
  606. * fdDriveSelect - select and turn on the specified drive.
  607. *
  608. * Select and turn on the specified drive.
  609. *
  610. * RETURNS: N/A
  611. */
  612. LOCAL void fdDriveSelect
  613.     (
  614.     int fdType,
  615.     int drive
  616.     )
  617.     {
  618.     FD_TYPE *pType = &fdTypes[fdType];
  619.     UCHAR command[12];
  620.     /* turn on the motor */
  621.     sysOutByte (FD_REG_OUTPUT, fdDORvalues[drive]);
  622.     sysDelay ();
  623.     /* set data rate */
  624.     sysOutByte (FD_REG_CONFIG, pType->dataRate);
  625.     sysDelay ();
  626.     command[0] = FD_CMD_SPECIFY;
  627.     command[1] = (pType->stepRate << 4) | pType->headUnload;
  628.     command[2] = pType->headLoad << 1;
  629.     fdCmdSend (command, FD_CMD_LEN_SPECIFY);
  630.     sysDelay ();
  631. #ifdef FD_DEBUG
  632.     printErr ("fdDriveSelectn");
  633. #endif /* FD_DEBUG */
  634.     }
  635. /*******************************************************************************
  636. *
  637. * fdDriveRelease - release and turn off the specified drive.
  638. *
  639. * Release and turn off the specified drive.
  640. *
  641. * RETURNS: N/A
  642. */
  643. LOCAL void fdDriveRelease (void)
  644.     {
  645.     /* turn off the motor */
  646.     sysOutByte (FD_REG_OUTPUT, (FD_DOR_CLEAR_RESET | FD_DOR_DMA_ENABLE));
  647.     sysDelay ();
  648.     }
  649. /*******************************************************************************
  650. *
  651. * fdIntSense - get information concerning the last drive interrupt
  652. *
  653. * Get information concerning the last drive interrupt
  654. *
  655. * RETURNS: OK, ERROR if the command didn't succeed.
  656. */
  657. LOCAL STATUS fdIntSense
  658.     (
  659.     int seekEnd
  660.     )
  661.     {
  662.     UCHAR rValue;
  663.     UCHAR command[12];
  664.     UCHAR results[12];
  665.     command[0] = FD_CMD_SENSEINT;
  666. #ifdef FD_DEBUG
  667.     {
  668.     int ix;
  669.     printErr ("fdIntSense: ");
  670.     for (ix = 0; ix < FD_CMD_LEN_SENSEINT; ix++)
  671.         printErr ("0x%x ", command[ix]);
  672.     printErr (" intCnt=%dn", fdIntCount);
  673.     }
  674. #endif /* FD_DEBUG */
  675.     fdCmdSend (command, FD_CMD_LEN_SENSEINT);
  676.     rValue = fdResultPhase (results, TRUE, 2);
  677.     if ((rValue == 0) && (seekEnd == 0) &&
  678. (((results[0] & 0xc0) == 0x00) || ((results[0] & 0xc0) == 0xc0)))
  679. return (OK);
  680.     else if ((rValue == 0) && (seekEnd == 1) && ((results[0] & 0xe0) == 0x20))
  681. return (OK);
  682. #ifdef FD_DEBUG
  683.     printErr ("fdIntSense: rValue=0x%x r0=0x%x 0x%xn",
  684.               rValue, results[0], results[1]);
  685. #endif /* FD_DEBUG */
  686.     return (ERROR);
  687.     }
  688. /*******************************************************************************
  689. *
  690. * fdRecalib - recalibrate the drive
  691. *
  692. * Recalibrate the drive
  693. *
  694. * RETURNS: OK, ERROR if the command didn't succeed.
  695. */
  696. LOCAL STATUS fdRecalib
  697.     (
  698.     int drive
  699.     )
  700.     {
  701.     int ix;
  702.     UCHAR rValue[2];
  703.     UCHAR command[12];
  704.     command[0] = FD_CMD_RECALIBRATE;
  705.     command[1] = drive & 0x03;
  706. #ifdef FD_DEBUG
  707.     {
  708.     printErr ("fdRecalib: ");
  709.     for (ix = 0; ix < FD_CMD_LEN_RECALIBRATE; ix++)
  710.         printErr ("0x%x ", command[ix]);
  711.     printErr (" intCnt=%dn", fdIntCount);
  712.     }
  713. #endif /* FD_DEBUG */
  714.     for (ix = 0; ix < 2; ix++)
  715. {
  716.         fdCmdSend (command, FD_CMD_LEN_RECALIBRATE);
  717.         if (semTake (&fdSyncSem, sysClkRateGet() * fdSemSec) != OK)
  718.     return (ERROR);
  719.         rValue[ix] = fdIntSense (1);
  720. }
  721.     if ((rValue[0] == OK) && (rValue[1] == OK))
  722. return (OK);
  723. #ifdef FD_DEBUG
  724.     printErr ("fdRecalib: rValue=0x%x 0x%xn", rValue[0], rValue[1]);
  725. #endif /* FD_DEBUG */
  726.     return (ERROR);
  727.     }
  728. /*******************************************************************************
  729. *
  730. * fdSeek - seek the drive heads to the specified cylinder
  731. *
  732. * Seek the drive heads to the specified cylinder
  733. *
  734. * RETURNS: OK, ERROR if the command didn't succeed.
  735. */
  736. LOCAL STATUS fdSeek
  737.     (
  738.     int drive,
  739.     int cylinder,
  740.     int head
  741.     )
  742.     {
  743.     UCHAR rValue;
  744.     UCHAR command[12];
  745.     command[0] = FD_CMD_SEEK;
  746.     command[1] = (head << 2) | (drive & 0x03);
  747.     command[2] = cylinder;
  748. #ifdef FD_DEBUG
  749.     {
  750.     int ix;
  751.     printErr ("fdSeek: ");
  752.     for (ix = 0; ix < FD_CMD_LEN_SEEK; ix++)
  753.         printErr ("0x%x ", command[ix]);
  754.     printErr (" intCnt=%dn", fdIntCount);
  755.     }
  756. #endif /* FD_DEBUG */
  757.     fdCmdSend (command, FD_CMD_LEN_SEEK);
  758.     if (semTake (&fdSyncSem, sysClkRateGet() * fdSemSec) != OK)
  759. return (ERROR);
  760.     rValue = fdIntSense (1);
  761.     if (rValue == OK)
  762. return (OK);
  763. #ifdef FD_DEBUG
  764.     printErr ("fdSeek: rValue=0x%xn", rValue);
  765. #endif /* FD_DEBUG */
  766.     return (ERROR);
  767.     }
  768. /*******************************************************************************
  769. *
  770. * fdRW - read/write a number of sectors on the current track
  771. *
  772. * Read/write a number of sectors on the current track
  773. *
  774. * RETURNS: OK, ERROR if the command didn't succeed.
  775. */
  776. LOCAL STATUS fdRW
  777.     (
  778.     int fdType,
  779.     int drive,
  780.     int cylinder,
  781.     int head,
  782.     int sector,
  783.     void *pBuf,
  784.     int nSecs,
  785.     int direction
  786.     )
  787.     {
  788.     FD_TYPE *pType = &fdTypes[fdType];
  789.     UCHAR rValue;
  790.     char fd_mt = 0;
  791.     unsigned nBytes = nSecs * (128 << pType->secSize);
  792.     UCHAR command[12];
  793.     UCHAR results[12];
  794.     if (pType->heads > 1)
  795. fd_mt = 1;
  796.     /* setup DMA controller */
  797.     if (direction == O_RDONLY)
  798. {
  799.         if (dmaSetup (O_RDONLY, (void *)sysFdBuf, nBytes, FD_DMA_CHAN) != OK)
  800.     return (ERROR);
  801.         command[0] = FD_CMD_READ | (fd_mt << 7) | (pType->mfm << 6) |
  802.  (pType->sk << 5);
  803. }
  804.     else
  805. {
  806.         if (dmaSetup (O_WRONLY, (void *)sysFdBuf, nBytes, FD_DMA_CHAN) != OK)
  807.     return (ERROR);
  808.         command[0] = FD_CMD_WRITE | (fd_mt << 7) | (pType->mfm << 6);
  809. bcopy ((char *)pBuf, (char *)sysFdBuf, nBytes);
  810. }
  811.     command[1] = (head << 2) | (drive & 0x03);
  812.     command[2] = cylinder;
  813.     command[3] = head;
  814.     command[4] = sector;
  815.     command[5] = pType->secSize;
  816.     command[6] = pType->sectorsTrack;
  817.     command[7] = pType->gap1;
  818.     command[8] = 0xff;
  819. #ifdef FD_DEBUG
  820.     {
  821.     int ix;
  822.     printErr ("fdRW %c : ", (direction == O_RDONLY) ? 'R' : 'W');
  823.     for (ix = 0; ix < FD_CMD_LEN_RW; ix++)
  824.         printErr ("0x%x ", command[ix]);
  825.     printErr (" intCnt=%dn", fdIntCount);
  826.     }
  827. #endif /* FD_DEBUG */
  828.     fdCmdSend (command, FD_CMD_LEN_RW);
  829.     if (semTake (&fdSyncSem, sysClkRateGet() * fdSemSec) != OK)
  830. return (FD_DISK_NOT_PRESENT);
  831.     rValue = fdResultPhase (results, FALSE, 7);
  832.     if (rValue == 0)
  833. {
  834. if ((results[0] & 0xc0) == 0x00)
  835.     {
  836.             if (direction == O_RDONLY)
  837.         bcopy ((char *)sysFdBuf, (char *)pBuf, nBytes);
  838.     return (OK);
  839.     }
  840. else
  841.     {
  842.     if ((results[1] & 0x04) == 0x04)
  843. return (FD_UNFORMATED);
  844.     else if ((results[1] & 0x02) == 0x02)
  845. return (FD_WRITE_PROTECTED);
  846.     else
  847. return (ERROR);
  848.     }
  849. }
  850. #ifdef FD_DEBUG
  851.     printErr ("fdRW %c : ", (direction == O_RDONLY) ? 'R' : 'W');
  852.     printErr ("rValue=0x%x r0=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xn",
  853.                rValue, results[0], results[1], results[2],
  854.                results[3], results[4], results[5], results[6]);
  855. #endif /* FD_DEBUG */
  856.     return (ERROR);
  857.     }
  858. /*******************************************************************************
  859. *
  860. * fdFormat - format the current track
  861. *
  862. * format the current track
  863. *
  864. * RETURNS: OK, ERROR if the command didn't succeed.
  865. */
  866. LOCAL STATUS fdFormat
  867.     (
  868.     int fdType,
  869.     int drive,
  870.     int cylinder,
  871.     int head,
  872.     int interleave
  873.     )
  874.     {
  875.     FD_TYPE *pType = &fdTypes[fdType];
  876.     int ix;
  877.     int sector;
  878.     UCHAR rValue;
  879.     UCHAR command[12];
  880.     UCHAR results[12];
  881.     char *pBuf = (char *)sysFdBuf;
  882.     sector = 1;
  883.     for (ix = 0; ix < pType->sectorsTrack; ix++)
  884. {
  885. *pBuf++ = (char)cylinder;
  886. *pBuf++ = (char)head;
  887. *pBuf++ = (char)sector;
  888. *pBuf++ = (char)pType->secSize;
  889. sector += 1; /* XXX no interleave yet */
  890. }
  891.     /* setup DMA controller */
  892.     if (dmaSetup (O_WRONLY, (void *)sysFdBuf, pType->sectorsTrack * 4,
  893.   FD_DMA_CHAN) != OK)
  894. return (ERROR);
  895.     command[0] = FD_CMD_FORMAT | (pType->mfm << 6);
  896.     command[1] = (head << 2) | (drive & 0x03);
  897.     command[2] = pType->secSize;
  898.     command[3] = pType->sectorsTrack;
  899.     command[4] = pType->gap2;
  900.     command[5] = 0xff;
  901. #ifdef FD_DEBUG
  902.     {
  903.     printErr ("fdFormat: ");
  904.     for (ix = 0; ix < FD_CMD_LEN_FORMAT; ix++)
  905.         printErr ("0x%x ", command[ix]);
  906.     printErr (" intCnt=%dn", fdIntCount);
  907.     }
  908. #endif /* FD_DEBUG */
  909.     fdCmdSend (command, FD_CMD_LEN_FORMAT);
  910.     if (semTake (&fdSyncSem, sysClkRateGet() * fdSemSec) != OK)
  911. return (ERROR);
  912.     rValue = fdResultPhase (results, FALSE, 7);
  913.     if ((rValue == 0) && ((results[0] & 0xc0) == 0x00))
  914. return (OK);
  915. #ifdef FD_DEBUG
  916.     printErr ("fdFmt: rValue=0x%x r0=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%xn",
  917.               rValue, results[0], results[1], results[2],
  918.               results[3], results[4], results[5], results[6]);
  919. #endif /* FD_DEBUG */
  920.     return (ERROR);
  921.     }
  922. /*******************************************************************************
  923. *
  924. * fdCmdSend - send commands to the chip
  925. *
  926. * Send commands to the chip
  927. *
  928. * RETURNS: 0, -1 or -2 if the command didn't succeed.
  929. */
  930. LOCAL int fdCmdSend
  931.     (
  932.     UCHAR *pCommand,
  933.     int nBytes
  934.     )
  935.     {
  936.     int timeout;
  937.     int ix;
  938.     /* send the command to the FDC */
  939.     for (ix = 0; ix < nBytes; ix++)
  940. {
  941. /* wait for the RQM flag */
  942. timeout = 0;
  943. while ((sysInByte (FD_REG_STATUS) & FD_MSR_RQM) != FD_MSR_RQM)
  944.     {
  945.     if (++timeout > fdTimeout)
  946. return (-1);
  947.     }
  948. /* check that the FDC is ready for input */
  949. if ((sysInByte (FD_REG_STATUS) & FD_MSR_DIRECTION) != 0)
  950.     return (-2);
  951. sysOutByte (FD_REG_DATA, (*pCommand++));
  952. sysDelay ();
  953. }
  954.     
  955.     return (0);
  956.     }
  957. /*******************************************************************************
  958. *
  959. * fdResultPhase - get results from the chip
  960. *
  961. * Get results from the chip
  962. *
  963. * RETURNS: 0, -1 -2 -3 -4 if the command didn't succeed.
  964. */
  965. LOCAL int fdResultPhase
  966.     (
  967.     UCHAR *pResults,
  968.     BOOL immediate,
  969.     int nBytes
  970.     )
  971.     {
  972.     int ix;
  973.     int timeout;
  974.     /* input results from the FDC */
  975.     if (immediate || (sysInByte (FD_REG_STATUS) & FD_MSR_FD_BUSY) != 0)
  976. {
  977. /* operation is completed, get FDC result bytes */
  978. for (ix = 0; ix < nBytes; ix++)
  979.     {
  980.     /* wait for the RQM flag */
  981.     timeout = 0;
  982.     while ((sysInByte (FD_REG_STATUS) & FD_MSR_RQM) != FD_MSR_RQM)
  983.         {
  984.         if (++timeout > fdTimeout)
  985.     return (-1);
  986.         }
  987.     /* check that the FDC is ready for output */
  988.     if ((sysInByte (FD_REG_STATUS) & FD_MSR_DIRECTION) == 0)
  989.         return (-2);
  990.     
  991.     pResults[ix] = sysInByte (FD_REG_DATA);
  992.     sysDelay ();
  993.     }
  994. /* make sure that FDC has completed sending data */
  995. timeout = 0;
  996. while ((sysInByte (FD_REG_STATUS) & FD_MSR_FD_BUSY) != 0)
  997.     {
  998.     if (++timeout > fdTimeout)
  999.         return (-3);
  1000.     }
  1001. #ifdef FD_DEBUG
  1002. {
  1003. printErr ("fdResultPhase: ");
  1004. for (ix = 0; ix < nBytes; ix++)
  1005.     printErr ("0x%x ", pResults[ix]);
  1006. printErr ("n");
  1007. }
  1008. #endif /* FD_DEBUG */
  1009. }
  1010.     else
  1011. {
  1012. /* catch all hidden interrupts */
  1013. ix = 0;
  1014. while (fdIntSense(0) != OK)
  1015.     {
  1016.     if (++ix > fdRetry)
  1017. return (-4);
  1018.     }
  1019. }
  1020.     return (0);
  1021.     }
  1022. /*******************************************************************************
  1023. *
  1024. * fdDriveIsWP - determine if the diskette has write protect tab set.
  1025. *
  1026. * This function will use the mode sense command to check the status
  1027. * of the write protect line.  The drive should be powered on before
  1028. * calling this routine, else the data is not valid.
  1029. *
  1030. * RETURNS: TRUE if WP tab is enabled / FALSE if it isn't;
  1031. */
  1032. LOCAL int fdDriveIsWP 
  1033.     (
  1034.     int drive /* drive to check WP tab on */
  1035.     )
  1036.     {
  1037.     UCHAR command[2];   /* two byte array for the command phase */
  1038.     UCHAR result; /* one byte for the result phase (st3) */
  1039.     /* setup sense drive command data */
  1040.     command[0] = FD_CMD_SENSEDRIVE;
  1041.     command[1] = drive & 0x03;  /* don't care about the head in this command */
  1042.     /* send sense drive status command, which is a two byte command */
  1043.     fdCmdSend (command, FD_CMD_LEN_SENSEDRIVE);
  1044.     /* get result of command (status reg three) and check WP bit is set */
  1045.     fdResultPhase(&result, FALSE, 1);
  1046.     /* Is bit 6 set in the result phase data? aka st3 */
  1047.     if ((result & 0x40) == 0x40)
  1048. {
  1049. #ifdef FD_DEBUG
  1050.         printErr ("fdDriveIsWP: write protect detected on.n");
  1051. #endif /* FD_DEBUG */
  1052. return (TRUE); /* WP Tab is set */
  1053. }
  1054.     else
  1055. {
  1056. #ifdef FD_DEBUG
  1057.         printErr ("fdDriveIsWP: write protect detected off.n");
  1058. #endif /* FD_DEBUG */
  1059. return (FALSE); /* WP Tab is not set */
  1060. }
  1061.     }