home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / ps0 / ps0.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  8.3 KB  |  384 lines

  1. /*
  2.  * ps0 - a simple device driver for raw floppy disks
  3.  *
  4.  * This program is written by Dave Gymer and is hereby placed in
  5.  * the public domain.
  6.  * The code is based on the clock device by Eric R Smith.
  7.  *
  8.  * Some improvements you could make:
  9.  *    - ioctl calls to reset disk characteristics on the fly
  10.  *    - maybe an ioctl call to format a track or whole disk
  11.  *    - command line arguments during installation governing which drive
  12.  *     to use
  13.  *    - write Floprd(2) and Flopwr(2) in this code to aboid calling the
  14.  *    Xbios altogether, and also allow it to do hard disks, too (bloody
  15.  *    dangerous if you can overwrite the boot block!)
  16.  *    - write TOS/minix-ST/minix-PC filing systems that use this (in a hard
  17.  *    disk version, most likely) instead of Rwabs(2) [ya think I'm kiddin?]
  18.  */
  19.  
  20. #include <minimal.h>
  21. #include <osbind.h>
  22. #include <basepage.h>
  23. #include <mintbind.h>
  24. #include "filesys.h"
  25. #include "atarierr.h"
  26.  
  27. /* characteristics of the floppy in question */
  28. #define DRIVE    0    /* BIOS drive number, 0 == A:, 1 == B: */
  29. #define TRACKS    80    /* tracks per disk */
  30. #define SIDES    2    /* sides per track */
  31. #define SECTORS    9    /* sectors per track */
  32. #define SECSIZE    512L    /* bytes per sector */
  33. #define BLOCKSIZE (SECSIZE * SECTORS)
  34.  
  35. /* the name of the device we're installing */
  36. /* I call mine /dev/ps0, cos that's what it's called on my Linux PC. */
  37. char name[] = "U:\\dev\\ps0";
  38.  
  39. /* kernel information */
  40. struct kerinfo *kernel;
  41. #define TGETTIME (*kernel->dos_tab[0x2c])
  42. #define TGETDATE (*kernel->dos_tab[0x2a])
  43.  
  44. #define SPRINTF (*kernel->sprintf)
  45. #define DEBUG (*kernel->debug)
  46. #define ALERT (*kernel->alert)
  47. #define TRACE (*kernel->trace)
  48. #define FATAL (*kernel->fatal)
  49. #define KMALLOC(sz) (*kernel->kmalloc)((long) (sz))
  50. #define KFREE (*kernel->kfree)
  51.  
  52. /* assumption: 16 bit shorts if !__MSHORT__ and 16 bit ints if __MSHORT__ */
  53. #ifdef __MSHORT__
  54. #define word int
  55. #else
  56. #define word short
  57. #endif
  58.  
  59. /* device driver information */
  60. static long    floppy_open    P_((FILEPTR *)),
  61.         floppy_write    P_((FILEPTR *, char *, long)),
  62.         floppy_read    P_((FILEPTR *, char *, long)),
  63.         floppy_lseek    P_((FILEPTR *, long, word)),
  64.         floppy_ioctl    P_((FILEPTR *, word, void *)),
  65.         floppy_datime    P_((FILEPTR *, word *, word)),
  66.         floppy_close    P_((FILEPTR *));
  67.  
  68. static long     floppy_select();
  69. static void    floppy_unselect();
  70.  
  71. DEVDRV floppy_device = {
  72.     floppy_open, floppy_write, floppy_read, floppy_lseek, floppy_ioctl,
  73.     floppy_datime, floppy_close, floppy_select, floppy_unselect,
  74.     0, 0, 0
  75. };
  76.  
  77. struct dev_descr devinfo = {
  78.     &floppy_device, 0, 0, (struct tty *)0, 0L, 0L, 0L, 0L
  79. };
  80.  
  81. /* Install time, for floppy_datime. */
  82.  
  83. static word install_date;
  84. static word install_time;
  85.  
  86. /* structure to hold a block buffer */
  87. typedef struct floppy_block {
  88.     int track;
  89.     int side;
  90.     long byte;
  91.     enum { INVALID, VALID, DIRTY, ATEOF } state;
  92.     char *buffer;
  93. } FLOBLOCK;
  94.  
  95. /*
  96.  * the main program just installs the device, and then does Ptermres
  97.  * to remain resident
  98.  */
  99.  
  100. main()
  101. {
  102.     kernel = (struct kerinfo *)Dcntl(DEV_INSTALL, name, &devinfo);
  103.     if (!kernel || ((long) kernel) == -32) {
  104.         Cconws("Unable to install floppy device\r\n");
  105.         Pterm(1);
  106.     }
  107.     install_time = TGETTIME();
  108.     install_date = TGETDATE();
  109.     Ptermres(256L + _base->p_tlen + _base->p_dlen + _base->p_blen, 0);
  110. }
  111.  
  112. /*
  113.  * utility functions
  114.  * note that blocks are whole tracks
  115.  */
  116.  
  117. /* read a block */
  118.  
  119. static int
  120. read_block(floblock)
  121.     FLOBLOCK *floblock;
  122. {
  123.     int rv;
  124.  
  125.     rv = Floprd(floblock->buffer, 0L, DRIVE, 1,
  126.             floblock->track, floblock->side, SECTORS);
  127.     if (rv) {
  128.         DEBUG("Floprd failed in read_buf");
  129.         floblock->state = INVALID;
  130.     } else
  131.         floblock->state = VALID;
  132.     return rv;
  133. }
  134.  
  135. /* flush a block */
  136.  
  137. static int
  138. flush_block(floblock)
  139.     FLOBLOCK *floblock;
  140. {
  141.     int rv;
  142.  
  143.     if (floblock->state != DIRTY)
  144.         return 0;
  145.     rv = Flopwr(floblock->buffer, 0L, DRIVE, 1,
  146.             floblock->track, floblock->side, SECTORS);
  147.     if (rv)
  148.         DEBUG("Flopwr failed in flush_block");
  149.     else
  150.         floblock->state = VALID;
  151.     return rv;
  152. }
  153.  
  154. /* convert long seek position into floppy_block */
  155.  
  156. static void
  157. seek2int(pos, floblock)
  158.     long pos;
  159.     FLOBLOCK *floblock;
  160. {
  161.     if (pos < 0)
  162.         pos = 0;
  163.     floblock->byte = pos % BLOCKSIZE;
  164.     pos /= BLOCKSIZE;
  165.     floblock->side = pos % SIDES;
  166.     pos /= SIDES;
  167.     floblock->track = pos;
  168.     if (floblock->track >= TRACKS) {
  169.         floblock->track = TRACKS;
  170.         floblock->side = 0;
  171.         floblock->byte = 0;
  172.         floblock->state = ATEOF;
  173.     }
  174. }
  175.  
  176. /* convert floppy_block into long seek position */
  177.  
  178. static long
  179. int2seek(floblock)
  180.     FLOBLOCK *floblock;
  181. {
  182.     return ((long) floblock->track * SIDES + floblock->side) * BLOCKSIZE
  183.         + floblock->byte;
  184. }
  185.  
  186. /* move to next block - read it, after flushing the old one */
  187.  
  188. static int
  189. next_block(floblock)
  190.     FLOBLOCK *floblock;
  191. {
  192.     int rv = 0;
  193.  
  194.     if (floblock->state != ATEOF) {
  195.         rv = flush_block(floblock);
  196.         if (++floblock->side == SIDES) {
  197.             floblock->side = 0;
  198.             if (++floblock->track == TRACKS) {
  199.                 floblock->state = ATEOF;
  200.                 floblock->side = 0;
  201.             }
  202.         }
  203.         if (floblock->state != ATEOF)
  204.             if (rv)
  205.                 floblock->state = INVALID;
  206.             else
  207.                 rv = read_block(floblock);
  208.         floblock->byte = 0;
  209.     }
  210.     return rv;
  211. }
  212.  
  213. /*
  214.  * here are the actual device driver functions
  215.  */
  216.  
  217. static long
  218. floppy_open(f)
  219.     FILEPTR *f;
  220. {
  221.     int rv;
  222.     FLOBLOCK *floblock = (FLOBLOCK *) KMALLOC(sizeof(FLOBLOCK));
  223.  
  224.     if (!floblock)
  225.         return ENSMEM;
  226.     floblock->buffer = (char *) KMALLOC(BLOCKSIZE);
  227.     if (!floblock->buffer)
  228.         return ENSMEM;
  229.     f->devinfo = (long) floblock;
  230.     floblock->state = INVALID;
  231.     floblock->track = 0;
  232.     floblock->side = 0;
  233.     floblock->byte = 0;
  234.     return 0;
  235. }
  236.  
  237. static long
  238. floppy_write(f, buf, bytes)
  239.     FILEPTR *f; char *buf; long bytes;
  240. {
  241.     FLOBLOCK *floblock = (FLOBLOCK *) f->devinfo;
  242.     int rv = 0;
  243.     long bytes_written = 0;
  244.  
  245.     if (floblock->state == INVALID)    /* not started yet */
  246.         rv = read_block(floblock);
  247.  
  248.     /* keep going until we've written enough, or there's an error or EOF */
  249.     while (!rv && floblock->state != ATEOF && bytes) {
  250.         if (floblock->byte < BLOCKSIZE) {    /* data in buffer */
  251.             char *ptr = floblock->buffer + floblock->byte;
  252.             long num = BLOCKSIZE - floblock->byte;
  253.  
  254.             if (num > bytes)
  255.                 num = bytes;
  256.             bytes_written += num;
  257.             bytes -= num;
  258.             floblock->byte += num;
  259.             while (num--)
  260.                 *ptr++ = *buf++;
  261.             floblock->state = DIRTY;
  262.         } else        /* must get next block */
  263.             rv = next_block(floblock);
  264.     }
  265.     return rv ? rv : bytes_written;
  266. }
  267.  
  268. static long
  269. floppy_read(f, buf, bytes)
  270.     FILEPTR *f; char *buf; long bytes;
  271. {
  272.     FLOBLOCK *floblock = (FLOBLOCK *) f->devinfo;
  273.     int rv = 0;
  274.     long bytes_read = 0;
  275.  
  276.     if (floblock->state == INVALID)    /* not started yet */
  277.         rv = read_block(floblock);
  278.  
  279.     /* keep going until we've read enough, or there's an error or EOF */
  280.     while (!rv && floblock->state != ATEOF && bytes) {
  281.         if (floblock->byte < BLOCKSIZE) {    /* data in buffer */
  282.             char *ptr = floblock->buffer + floblock->byte;
  283.             long num = BLOCKSIZE - floblock->byte;
  284.  
  285.             if (num > bytes)
  286.                 num = bytes;
  287.             bytes_read += num;
  288.             bytes -= num;
  289.             floblock->byte += num;
  290.             while (num--)
  291.                 *buf++ = *ptr++;
  292.         } else        /* must get next block */
  293.             rv = next_block(floblock);
  294.     }
  295.     return rv ? rv : bytes_read;
  296. }
  297.  
  298. static long
  299. floppy_lseek(f, where, whence)
  300.     FILEPTR *f; long where; word whence;
  301. {
  302.     long newpos = where;
  303.     FLOBLOCK *floblock = (FLOBLOCK *) f->devinfo;
  304.  
  305.     switch (whence) {
  306.         case SEEK_SET:
  307.             break;
  308.         case SEEK_CUR:
  309.             newpos += int2seek(floblock);
  310.             break;
  311.         case SEEK_END:
  312.             newpos = SIDES * TRACKS * BLOCKSIZE - newpos;
  313.             break;
  314.         default:
  315.             DEBUG("ps0: illegal whence (%d) in seek", whence);
  316.             return ERANGE;
  317.     }
  318.     if (int2seek(floblock) % BLOCKSIZE != newpos % BLOCKSIZE) {
  319.         if (flush_block(floblock))
  320.             DEBUG("flush_block failed in floppy_lseek");
  321.         floblock->state = INVALID;
  322.     }
  323.     seek2int(newpos, floblock);
  324.     return newpos;
  325. }
  326.  
  327. static long
  328. floppy_ioctl(f, mode, buf)
  329.     FILEPTR *f; word mode; void *buf;
  330. {
  331.     switch (mode) {
  332.         case FIONREAD:
  333.         case FIONWRITE:
  334.             /*
  335.              * we never block - use BLOCKSIZE as a sensible
  336.              * number to read as a chunk
  337.              */
  338.             *((long *) buf) = BLOCKSIZE;
  339.             return 0;
  340.         default:
  341.             return EINTRN;
  342.     }
  343. }
  344.  
  345. static long
  346. floppy_datime(f, timeptr, wrflag)
  347.     FILEPTR *f;
  348.     word *timeptr;
  349.     word wrflag;
  350. {
  351.     if (wrflag)
  352.         return EINVFN;
  353.     *timeptr++ = install_time;
  354.     *timeptr++ = install_date;
  355.     return 0;
  356. }
  357.  
  358. static long
  359. floppy_close(f)
  360.     FILEPTR *f;
  361. {
  362.     int rv = 0;
  363.     FLOBLOCK *floblock = (FLOBLOCK *) f->devinfo;
  364.  
  365.     if (!f->links) {
  366.         rv = flush_block(floblock);    /* flush the buffer */
  367.         KFREE(floblock->buffer);
  368.         KFREE(floblock);
  369.     }
  370.     return rv;
  371. }
  372.  
  373. static long
  374. floppy_select()
  375. {
  376.     return 1;    /* we're always ready for I/O */
  377. }
  378.  
  379. static void
  380. floppy_unselect()
  381. {
  382.     /* nothing for us to do here */
  383. }
  384.