leo@marco.UUCP (Matthias Pfaller) (03/13/90)
This is a floppy-driver that allows you to read/write/format floppys with
sectorsizes other then 512 bytes. You also can change the number of tracks
and the number of sectors/track for each drive.
If you have connected a 10.24 Mhz oscillator to your floppy controller and
made it switchable via bit 7, sound-chip port A, you can use the higher
density for minix. I recommend 7 sectors with 1k per track.
leo@marco.uucp (Matthias Pfaller)
PS: I would like to get some feedback (also for my patch for the st-harddisk
driver I posted recently)
echo x - fdctrl.c
sed '/^X/s///' > fdctrl.c << '/'
X#include <stdio.h>
X#include <fcntl.h>
X#include <sgtty.h>
X
Xmain(argc, argv)
Xint argc; char **argv;
X{
X struct fd_ioctl fdio;
X int sfd;
X int cyl = 0, sec = 0, len = 0;
X extern char *optarg;
X extern int optind;
X register char c;
X static char usage[] = "Usage: %s [-c cylinders] [-s sectors] [-l sectorlen] raw_device\n";
X
X while ((c = getopt(argc, argv, "c:s:l:")) != EOF)
X {
X switch(c)
X {
X case 'c':
X cyl = atoi(optarg);
X break;
X
X case 's':
X sec = atoi(optarg);
X break;
X
X case 'l':
X len = atoi(optarg);
X break;
X
X default:
X fprintf(stderr, usage, argv[0]);
X exit(1);
X }
X }
X
X if (!argv[optind])
X {
X fprintf(stderr, usage, argv[0]);
X exit(1);
X }
X
X sfd = open(argv[optind], O_RDONLY);
X if (sfd < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X
X if (ioctl(sfd, DIOCGETP, &fdio) < 0)
X {
X perror(argv[0]);
X fprintf(stderr, usage, argv[0]);
X exit(1);
X }
X else
X {
X if (cyl)
X fdio.nr_cylinders = cyl;
X if (sec)
X fdio.nr_sectors = sec;
X if (len)
X fdio.sector_size = len;
X }
X
X if (ioctl(sfd, DIOCSETP, &fdio) < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X
X fprintf(stderr, "sector_size = %d nr_sectors = %d nr_cylinders = %d\n", fdio.sector_size, fdio.nr_sectors, fdio.nr_cylinders);
X exit(0);
X}
/
echo x - flopfmt.c
sed '/^X/s///' > flopfmt.c << '/'
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/stat.h>
X#include <sgtty.h>
X
Xvoid memset(p, b, c)
Xregister char *p; register char b; register int c;
X{
X while(c--)
X *p++ = b;
X}
X
Xint gap3(spt, seclen, ahdr) /* computes the optimum size of gap3 */
Xint spt, seclen, ahdr; /* returns -1 for error */
X /* a rotation speed variation of 2% is */
X{ /* asumed */
X int gap3min;
X int gap3max;
X int gap4min;
X int ttc;
X
X ttc = (spt * seclen > 5120)?8000:6250;
X gap4min = ttc / 50;
X gap3max = (ttc - gap4min - 60 - (ahdr?22:0))/spt - (seclen + 62);
X gap3min = (seclen + 62)/50;
X return((gap3max < gap3min) ? -1:((gap3min + gap3max) / 2));
X}
X
Xchar *buildtrack(sectab, spt, track, side, virgin, seclen, ahdr)
Xchar *sectab; int spt, track, side, virgin, seclen, ahdr;
X{
X int gap3len, i;
X char *data, *malloc();
X register char *cp;
X
X cp = data = malloc(10000);
X if ((gap3len = gap3(spt, seclen, ahdr)) < 0)
X return(NULL);
X
X /* Track header */
X memset(cp, (char)0x4e, 60); cp += 60;
X
X for(i = 0; i < spt; i++)
X {
X /* additional header for sector 0 */
X if (ahdr && sectab[i] == 1)
X {
X /* sync */
X memset(cp, 0x00, 12); cp += 12;
X /* id-address mark */
X memset(cp, 0xf5, 3); cp += 3;
X *cp++ = 0xfe;
X /* id-field */
X *cp++ = track;
X *cp++ = side;
X *cp++ = 0;
X *cp++ = 0;
X /* write CRC- code */
X *cp++ = 0xf7;
X }
X
X /* sync */
X memset(cp, 0x00, 12); cp += 12;
X
X /* id-address mark */
X memset(cp, 0xf5, 3); cp += 3;
X *cp++ = 0xfe;
X
X /* id-field */
X *cp++ = track;
X *cp++ = side;
X *cp++ = sectab[i];
X switch(seclen)
X {
X case 128:
X *cp++ = 0;
X break;
X
X case 256:
X *cp++ = 1;
X break;
X
X case 512:
X *cp++ = 2;
X break;
X
X case 1024:
X *cp++ = 3;
X break;
X
X case 2048:
X *cp++ = 4;
X break;
X
X case 4096:
X *cp++ = 5;
X break;
X
X default:
X exit(1);
X }
X
X /* write CRC- code */
X *cp++ = 0xf7;
X
X /* gap2 */
X memset(cp, 0x4e, 22); cp += 22;
X memset(cp, 0x00, 12); cp += 12;
X
X /* data address mark */
X memset(cp, 0xf5, 3); cp += 3;
X *cp++ = 0xfb;
X
X /* data field */
X memset(cp, virgin, seclen);
X cp += seclen;
X
X /* write CRC- code */
X *cp++ = 0xf7;
X
X /* gap 3 */
X memset(cp, 0x4e, gap3len); cp += gap3len;
X }
X
X /* gap 4 */
X memset(cp, 0x4e, 10000 - (cp - data));
X return(data);
X}
X
Xmain(argc, argv)
Xint argc; char **argv;
X{
X register int i, j, s, sides;
X register char *p;
X extern char *rindex();
X int tfd, sfd;
X struct fd_ioctl tfdio, sfdio;
X struct stat statbuf;
X char b[80];
X
X extern char *optarg;
X extern int optind;
X int qflag = 0; /* quiet mode */
X int aflag = 0; /* additional 0 header */
X int interl = 1; /* sector interleave */
X int spiral = 1; /* track interleave */
X int c;
X static char usage[] = "Usage: %s [-q] [-i sector_interleave] [-t track_interleave] raw_device\n";
X
X char t[30], tc[30];
X
X while ((c = getopt(argc, argv, "qai:t:")) != EOF)
X {
X switch(c)
X {
X case 'q':
X qflag++;
X break;
X
X case 'a':
X aflag++;
X break;
X
X case 'i':
X interl = atoi(optarg);
X break;
X
X case 't':
X spiral = atoi(optarg);
X break;
X
X default:
X fprintf(stderr, usage, argv[0]);
X exit(1);
X }
X }
X
X if (!argv[optind])
X {
X fprintf(stderr, usage, argv[0]);
X exit(1);
X }
X
X sfd = open(argv[optind], O_RDONLY);
X if (sfd < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X p = rindex(argv[optind], '/');
X p = p?p + 1:argv[optind];
X *p = 't';
X tfd = open(argv[optind], O_WRONLY);
X if (tfd < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X if (ioctl(tfd, DIOCGETP, &tfdio) < 0 || ioctl(sfd, DIOCGETP, &sfdio) < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X if (fstat(tfd, &statbuf) < 0)
X {
X perror(argv[0]);
X exit(1);
X }
X if (!(statbuf.st_rdev & 0x20))
X {
X fprintf(stderr, "%s: no formatting device (devno = %d)\n", argv[0], statbuf.st_rdev);
X exit(1);
X }
X sides = statbuf.st_rdev & 0x8?2:1;
X
X for (i = 0; i < sfdio.nr_sectors; i++)
X t[i] = -1;
X
X for (i = 1, j = 0; i <= sfdio.nr_sectors; i++)
X {
X while (t[j] != -1)
X j = (j+1) % sfdio.nr_sectors;
X
X t[j] = i;
X j = (j+interl) % sfdio.nr_sectors;
X }
X
X if (!qflag)
X {
X printf("Sector sequence: ");
X for (i = 0; i < sfdio.nr_sectors; i++)
X printf(" %2d ", t[i]);
X printf("\n");
X }
X
X for (i = 0; i < sfdio.nr_cylinders; i++)
X {
X for (j = 0; j < sides; j++)
X {
X p = buildtrack(t, sfdio.nr_sectors, i, j, 0xe5, sfdio.sector_size, aflag);
X if (!p)
X {
X fprintf(stderr, "\n%s: track too long\n", argv[0]);
X exit(1);
X }
X
X if (!qflag)
X printf("Formatting track %02d side %d\r", i, j);
X
X if (write(tfd, p, tfdio.sector_size) < 0)
X {
X fprintf(stderr, "\n");
X perror(argv[0]);
X exit(1);
X }
X free(p);
X }
X
X for (j = 0; j < sfdio.nr_sectors; j++)
X tc[(j + spiral)%sfdio.nr_sectors] = t[j];
X
X for (j = 0; j < sfdio.nr_sectors; j++)
X t[j] = tc[j];
X }
X if (!qflag)
X printf("\n");
X exit(0);
X}
X
/
echo x - ioctl.c
sed '/^X/s///' > ioctl.c << '/'
X#include <lib.h>
X#include <minix/com.h>
X#include <sgtty.h>
X
XPUBLIC int ioctl(fd, request, argp)
Xint fd;
Xint request;
Xstruct sgttyb *argp;
X{
X int n;
X long erase, kill, intr, quit, xon, xoff, eof, brk, speed;
X struct tchars *argt;
X
X M.TTY_REQUEST = request;
X M.TTY_LINE = fd;
X
X switch(request) {
X case TIOCSETP:
X erase = argp->sg_erase & BYTE;
X kill = argp->sg_kill & BYTE;
X speed = ((argp->sg_ospeed & BYTE) << 8) | (argp->sg_ispeed & BYTE);
X M.TTY_SPEK = (speed << 16) | (erase << 8) | kill;
X M.TTY_FLAGS = argp->sg_flags;
X n = callx(FS, IOCTL);
X return(n);
X
X case DIOCSETP:
X case TIOCSETC:
X argt = (struct tchars * /* kludge */) argp;
X intr = argt->t_intrc & BYTE;
X quit = argt->t_quitc & BYTE;
X xon = argt->t_startc & BYTE;
X xoff = argt->t_stopc & BYTE;
X eof = argt->t_eofc & BYTE;
X brk = argt->t_brkc & BYTE; /* not used at the moment */
X M.TTY_SPEK = (intr<<24) | (quit<<16) | (xon<<8) | (xoff<<0);
X M.TTY_FLAGS = (eof<<8) | (brk<<0);
X n = callx(FS, IOCTL);
X return(n);
X
X case TIOCGETP:
X n = callx(FS, IOCTL);
X argp->sg_erase = (M.TTY_SPEK >> 8) & BYTE;
X argp->sg_kill = (M.TTY_SPEK >> 0) & BYTE;
X argp->sg_flags = M.TTY_FLAGS & 0xFFFFL;
X speed = (M.TTY_SPEK >> 16) & 0xFFFFL;
X argp->sg_ispeed = speed & BYTE;
X argp->sg_ospeed = (speed >> 8) & BYTE;
X return(n);
X
X case DIOCGETP:
X case TIOCGETC:
X n = callx(FS, IOCTL);
X argt = (struct tchars *) argp;
X argt->t_intrc = (M.TTY_SPEK >> 24) & BYTE;
X argt->t_quitc = (M.TTY_SPEK >> 16) & BYTE;
X argt->t_startc = (M.TTY_SPEK >> 8) & BYTE;
X argt->t_stopc = (M.TTY_SPEK >> 0) & BYTE;
X argt->t_eofc = (M.TTY_FLAGS >> 8) & BYTE;
X argt->t_brkc = (M.TTY_FLAGS >> 8) & BYTE;
X return(n);
X
X/* This is silly, do we want to add 1001 cases and M.TTY_XYZ's here?
X * We should just pop argp into the message for low-level interpretation.
X */
X
X case TIOCFLUSH:
X M.TTY_FLAGS = (int /* kludge */) argp;
X return callx(FS, IOCTL);
X
X default:
X n = -1;
X errno = -(EINVAL);
X return(n);
X }
X}
/
echo x - stfloppy.c
sed '/^X/s///' > stfloppy.c << '/'
X#if (MACHINE == ATARI)
X/*
X * This file contains a driver for the Floppy Disk Controller (FDC)
X * on the Atari ST. It uses the WD 1772 chip, modified for steprates.
X * The driver supports two operations: read a block and write a block.
X * It accepts four messages, for reading, for writing, for scattered
X * I/O and for control. All use message format m2 with these
X * parameters:
X *
X * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
X * ----------------------------------------------------------------
X * | DISK_READ | device | proc nr | bytes | offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * |SCATTERED_IO| device | proc nr | requests| | iov ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | DISK_IOCTL | device | proc nr |func code| spt etc | |
X * ----------------------------------------------------------------
X *
X * The file contains two entry points:
X *
X * floppy_task: main entry when system is brought up
X * fd_timer: used to deselect drives, called from clock.c
X *
X * The ST floppy disk controller shares the access to the DMA circuitry
X * with other devices. For this reason the floppy disk controller makes
X * use of some special DMA accessing code.
X *
X * Interrupts from the FDC are in fact DMA interrupts which get their
X * first level handling in stdma.c . If the floppy driver is currently
X * using DMA the interrupt is signalled to the floppy task.
X */
X
X#include "kernel.h"
X#include <minix/callnr.h>
X#include <minix/com.h>
X#include <sgtty.h>
X#include "proc.h"
X
X#include "staddr.h"
X#include "stfdc.h"
X#include "stdma.h"
X#include "stsound.h"
X
X#define ASSERT(x) if (!(x)) panic("fd: ASSERT(x) failed", NO_NUM);
X#define TRACE(x) /* x */
X#define DEBUG(x) x
X
X#define FDC_DELAY 32 /* for dma[rw]dat() */
X
X/* Parameters for the disk drive. */
X#define D_SECTOR_SIZE 512 /* physical sector size in bytes */
X#define D_NR_SECTORS 10 /* number of sectors per track */
X#define D_NR_CYLINDERS 82 /* number of cylinders */
X#define NR_DRIVES 2 /* maximum number of drives */
X#define NR_TYPES 8 /* number of diskette/drive combinations */
X#define MAX_ERRORS 10 /* how often to try rd/wt before quitting */
X#define SIDES 1 /* sides-mask in drive type */
X#define DENSE 2 /* hd/nd mask in drive type */
X#define FORMAT 4 /* format-mask in drive type */
X
X/*
X * The minor device number is build as follows
X * 00fhd00n
X * f = 1 -> formatting device
X * h = 1 -> high density (320 kbit) device
X * d = 1 -> double sided device
X * n = 0 -> select drive 0
X * n = 1 -> select drive 1
X * The index into the fparam table is computed by
X * ((DTYPE(minor) << 1)|DRIVE(minor))
X *
X * All parameters in fparam can be set by an ioctl-system call.
X * The nr_cylinders-field of the format device is allways set
X * to the value of the corresponding non-format device.
X * The parameters of format devices are read-only.
X */
X
Xstruct fparam { /* variable parameters for each minor device */
X int sector_size;
X char nr_sectors;
X char nr_cylinders;
X} fparam[16] = {
X { D_SECTOR_SIZE, D_NR_SECTORS, D_NR_CYLINDERS },
X { D_SECTOR_SIZE, D_NR_SECTORS, D_NR_CYLINDERS },
X { D_SECTOR_SIZE, D_NR_SECTORS, D_NR_CYLINDERS },
X { D_SECTOR_SIZE, D_NR_SECTORS, D_NR_CYLINDERS },
X { 1024, 7, D_NR_CYLINDERS },
X { 1024, 7, D_NR_CYLINDERS },
X { 1024, 7, D_NR_CYLINDERS },
X { 1024, 7, D_NR_CYLINDERS },
X { 6656, 1, D_NR_CYLINDERS },
X { 6656, 1, D_NR_CYLINDERS },
X { 6656, 1, D_NR_CYLINDERS },
X { 6656, 1, D_NR_CYLINDERS },
X { 8192, 1, D_NR_CYLINDERS },
X { 8192, 1, D_NR_CYLINDERS },
X { 8192, 1, D_NR_CYLINDERS },
X { 8192, 1, D_NR_CYLINDERS }
X};
X
X/* return values of xfer_ok(): */
X#define X_OK 0
X#define X_AGAIN 1
X#define X_ERROR 2
X#define X_FAIL 3
X
XPRIVATE int curcyl[NR_DRIVES]; /* current cylinder (-1 if not calibrated) */
X
XPRIVATE message mess; /* message buffer for in and out */
X
XPRIVATE struct xfer {
X int x_rw; /* read or write */
X int x_drive; /* drive number */
X int x_secnum; /* current sector */
X phys_bytes x_address; /* current physical address */
X int x_count; /* bytes still to transfer */
X int x_errors; /* errors on current sector */
X int x_cmd; /* controller command */
X} xfer;
X
X#define DRIVE(d) ((d) & 0x07)
X#define DTYPE(d) (((d) >> 3) & 0x1F)
X
Xstatic int do_open();
Xstatic int do_rdwt();
Xstatic int do_xfer();
Xstatic int select();
Xstatic void deselect();
Xstatic void fdcint();
Xstatic int xfer_done();
Xstatic int xfer_ok();
X
X/*===========================================================================*
X * floppy_task *
X *===========================================================================*/
XPUBLIC void floppy_task()
X{
X register r, drive, caller, procno;
X
X /*
X * The main loop of the disk task.
X * It waits for a message, carries it out, and sends a reply.
X */
X TRACE(printf("fd: task started\n"));
X
X dmagrab(FLOPPY, fdcint);
X dmawdat(FDC_CS, IRUPT, FDC_DELAY); /* reset controller */
X select(0, 0, 0);
X deselect();
X dmafree(FLOPPY);
X
X for (drive = 0; drive < NR_DRIVES; drive++)
X curcyl[drive] = -1; /* uncalibrated */
X while (TRUE) {
X receive(ANY, &mess);
X ASSERT(mess.m_source >= 0);
X TRACE(printf("fd: received %d from %d\n",mess.m_type,mess.m_source));
X caller = mess.m_source;
X procno = mess.PROC_NR;
X
X /* Now carry out the work. */
X switch (mess.m_type) {
X case DISK_READ:
X case DISK_WRITE: r = do_rdwt(&mess); break;
X case SCATTERED_IO: r = do_vrdwt(&mess, do_rdwt); break;
X case DISK_IOCTL: r = do_ioctl(&mess); break;
X default: r = EINVAL; break;
X }
X
X /* Finally, prepare and send the reply message. */
X mess.m_type = TASK_REPLY;
X mess.REP_PROC_NR = procno;
X mess.REP_STATUS = r; /* # of bytes transferred or error code */
X send(caller, &mess); /* send reply to caller */
X }
X}
X
X
X/*===========================================================================*
X * do_rdwt *
X *===========================================================================*/
XPRIVATE int do_rdwt(mp)
Xregister message *mp;
X{
X register struct xfer *xp;
X register struct fparam *f;
X register struct proc *rp;
X register nbytes;
X
X xp = &xfer;
X xp->x_rw = mp->m_type;
X xp->x_drive = mp->DEVICE;
X if (DRIVE(xp->x_drive) >= NR_DRIVES)
X return(EIO);
X if (DTYPE(xp->x_drive) >= NR_TYPES)
X return(EIO);
X if ((DTYPE(xp->x_drive) & FORMAT) && xp->x_rw == DISK_READ)
X return(EINVAL);
X
X f = fparam + (DTYPE(xp->x_drive)<<1) + DRIVE(xp->x_drive);
X nbytes = mp->COUNT;
X xp->x_count = nbytes;
X
X if ((mp->POSITION % f->sector_size) != 0)
X return(EINVAL);
X if ((nbytes % f->sector_size) != 0)
X return(EINVAL);
X xp->x_secnum = (int)(mp->POSITION/f->sector_size);
X rp = proc_addr(mp->PROC_NR);
X xp->x_address = umap(rp, D, (vir_bytes) mp->ADDRESS, (vir_bytes) nbytes);
X if (xp->x_address == 0)
X return(EINVAL);
X if (nbytes == 0)
X return(0);
X rp->p_physio = 1; /* disable (un)shadowing */
X dmagrab(FLOPPY, fdcint);
X xp->x_errors = 0;
X if (do_xfer()) {
X receive(HARDWARE, &mess);
X deselect();
X }
X dmafree(FLOPPY);
X rp->p_physio = 0; /* enable (un)shadowing */
X if (xp->x_count == nbytes)
X return(0); /* nothing transferred */
X if (xp->x_count != 0)
X return(EIO); /* partial transfer */
X return(nbytes);
X}
X
X/*===========================================================================*
X * do_xfer *
X *===========================================================================*/
XPRIVATE int do_xfer()
X{
X register struct xfer *xp;
X register struct fparam *f;
X register d, head, cylinder, sector, hbit, dense;
X static int ebit = 0;
X
X xp = &xfer;
X
X d = DTYPE(xp->x_drive);
X f = fparam + (d<<1) + DRIVE(xp->x_drive);
X cylinder = xp->x_secnum / f->nr_sectors;
X head = (d & SIDES)?cylinder & 1:0;
X cylinder = (d & SIDES)?cylinder >> 1:cylinder;
X if (cylinder >= f->nr_cylinders)
X return(0);
X
X dense = d & DENSE;
X xp->x_cmd = (xp->x_rw == DISK_READ)?F_READ:(d & FORMAT?WRITETR:F_WRITE);
X d = DRIVE(xp->x_drive);
X
X hbit = 0;
X if (select(d, head, dense) != 0)
X hbit = HBIT; /* motor on, suppress spin up sequence */
X
X if (curcyl[d] == -1) {
X /*
X * Recalibrate, since we lost track of head positioning.
X * The floppy disk controller has no way of determining its
X * absolute arm position (cylinder). Instead, it steps the
X * arm a cylinder at a time and keeps track of where it
X * thinks it is (in software). However, after a SEEK, the
X * hardware reads information from the diskette telling
X * where the arm actually is. If the arm is in the wrong place,
X * a recalibration is done, which forces the arm to cylinder 0.
X * This way the controller can get back into sync with reality.
X */
X TRACE(printf("fd%d: recalibrate\n", xp->x_drive));
X xp->x_cmd = RESTORE;
X dmawdat(FDC_CS, RESTORE|(dense?RATE6:RATE3)|hbit, FDC_DELAY);
X ebit = EBIT;
X return(1);
X }
X
X dmawdat(FDC_TR, curcyl[d], FDC_DELAY);
X
X /*
X * Issue a SEEK command on the indicated drive unless the arm is
X * already positioned on the correct cylinder.
X */
X if (cylinder != curcyl[d]) {
X curcyl[d] = cylinder; /* be optimistic */
X xp->x_cmd = SEEK;
X dmawdat(FDC_DR, cylinder, FDC_DELAY);
X dmawdat(FDC_CS, SEEK|(dense?RATE6:RATE3)|hbit, FDC_DELAY);
X ebit = EBIT;
X return(1);
X }
X
X /* The drive is now on the proper cylinder. Read or write 1 block. */
X sector = xp->x_secnum % f->nr_sectors;
X sector++; /* start numbering at 1 */
X
X TRACE(printf("fd%d: %s: secnum=%d,cylinder=%d,sector=%d,head=%d\n",
X xp->x_drive, xp->x_rw == DISK_READ ? "read" : "write",
X xp->x_secnum, cylinder, sector, head));
X
X dmawdat(FDC_SR, sector, FDC_DELAY);
X dmaaddr(xp->x_address); /* DMA address setup */
X
X if (xp->x_rw == DISK_READ) {
X /* Issue the command */
X dmacomm(FDC | SCREG, f->sector_size / 512, 0);
X dmawdat(FDC_CS, xp->x_cmd|hbit|ebit, FDC_DELAY);
X } else {
X /* Issue the command */
X dmacomm(WRBIT | FDC | SCREG, f->sector_size / 512, FDC_DELAY);
X dmawdat(WRBIT | FDC_CS, xp->x_cmd|hbit|ebit, FDC_DELAY);
X }
X ebit = 0;
X return(1);
X}
X
X/*===========================================================================*
X * select, deselect, fd_timer *
X *===========================================================================*/
X
XPRIVATE int selected; /* drive/head currently selected */
XPRIVATE int selectic = 30; /* # of fd_timer calls to deselect */
XPRIVATE int motoron; /* for how long will motor run? */
X
XPRIVATE int select(drive, head, dense)
Xint drive;
Xint head;
Xint dense;
X{
X register i, s, spinning;
X
X TRACE(printf("fd: select (drive %d, head %d)\n", drive, head));
X spinning = motoron;
X motoron = 5; /* will run for more than 500 msec */
X selectic = -30; /* error if not ready within 3 sec */
X i = (drive == 1 ? PA_FLOP1 : PA_FLOP0);
X i |= head;
X if (i != selected) {
X selected = i;
X s = lock();
X SOUND->sd_selr = YM_IOA;
X SOUND->sd_wdat = (SOUND->sd_rdat & 0x78) | (i ^ 0x07) | (dense?PA_FDDENS:0);
X restore(s);
X }
X return(spinning);
X}
X
XPRIVATE void deselect()
X{
X TRACE(printf("fd: deselect\n"));
X selectic = 30; /* postpone for 30 * 100 msec == 3 sec */
X}
X
XPUBLIC void fd_timer()
X{
X/*
X * Perform three functions:
X * 1. Estimate when motor stops running
X * 2. Force interrupt if drive does not respond
X * 3. Deselect drive(s) when all motors stopped spinning
X */
X register s, wrbit;
X
X if (selectic == 0)
X return;
X if (motoron)
X --motoron;
X if (selectic < 0) {
X if (++selectic == 0) {
X s = lock();
X wrbit = (xfer.x_cmd == F_WRITE || xfer.x_cmd == WRITETR) ?
X WRBIT : 0;
X xfer.x_cmd = IRUPT;
X dmawdat(FDC_CS, wrbit|IRUPT, FDC_DELAY);
X fdcint();
X restore(s);
X }
X return;
X }
X if (--selectic != 0)
X return;
X selected = 0;
X s = lock();
X SOUND->sd_selr = YM_IOA;
X SOUND->sd_wdat = SOUND->sd_rdat | 0x07;
X restore(s);
X}
X
X/*===========================================================================*
X * fdcint *
X *===========================================================================*/
XPRIVATE void fdcint()
X{
X ASSERT(xfer.x_count)
X if (xfer_done() == 0)
X return;
X interrupt(FLOPPY);
X}
X
X/*===========================================================================*
X * xfer_done *
X *===========================================================================*/
XPRIVATE int xfer_done()
X{
X register struct xfer *xp;
X register struct fparam *f;
X
X xp = &xfer;
X f = fparam + (DTYPE(xp->x_drive)<<1) + DRIVE(xp->x_drive);
X switch (xfer_ok()) {
X case X_FAIL:
X return(1);
X case X_ERROR:
X xp->x_errors++;
X if (xp->x_errors == MAX_ERRORS)
X return(1);
X break;
X case X_AGAIN:
X break;
X case X_OK:
X xp->x_errors = 0;
X xp->x_secnum++;
X xp->x_address += f->sector_size;
X xp->x_count -= f->sector_size;
X if (xp->x_count == 0)
X return(1);
X break;
X }
X if (do_xfer() == 0)
X return(1);
X return(0);
X}
X
X/*===========================================================================*
X * xfer_ok *
X *===========================================================================*/
XPRIVATE int xfer_ok()
X{
X register struct xfer *xp;
X register status;
X
X xp = &xfer;
X switch (xp->x_cmd) {
X case IRUPT:
X printf("fd%d: timeout\n", xp->x_drive);
X curcyl[DRIVE(xp->x_drive)] = -1;
X return(X_ERROR);
X case F_READ:
X /* Test for DMA error */
X status = dmastat(FDC_CS | SCREG, 0);
X if ((status & DMAOK) == 0) {
X printf("fd%d: read: dma status = 0x%x\n",
X xp->x_drive, DMA->dma_stat & BYTE);
X return(X_ERROR);
X }
X /* Get controller status and check for errors. */
X status = dmardat(FDC_CS, FDC_DELAY);
X if (status & (RNF | CRCERR | LD_T00)) {
X printf("fd%d: read sector %d: fdc status = 0x%x\n",
X xp->x_drive, xp->x_secnum, status&0xFF);
X if (xp->x_errors > 2)
X curcyl[DRIVE(xp->x_drive)] = -1;
X dmawdat(FDC_CS, IRUPT, FDC_DELAY); /* reset controller */
X return(X_ERROR);
X }
X break;
X case F_WRITE:
X case WRITETR:
X /* Test for DMA error */
X status = dmastat(FDC_CS | SCREG, 0);
X if ((status & DMAOK) == 0) {
X printf("fd%d: write: dma status = 0x%x\n",
X xp->x_drive, DMA->dma_stat & BYTE);
X dmawdat(FDC_CS, IRUPT, FDC_DELAY); /* reset controller */
X return(X_ERROR);
X }
X /* Get controller status and check for errors. */
X status = dmardat(WRBIT | FDC_CS, FDC_DELAY);
X if (status & WRI_PRO) {
X printf("fd%d: write protected\n", xp->x_drive);
X return(X_FAIL);
X }
X if (status & (RNF | CRCERR | LD_T00)) {
X printf("fd%d: write sector %d: fdc status = 0x%x\n",
X xp->x_drive, xp->x_secnum, status&0xFF);
X if (xp->x_errors > 2)
X curcyl[DRIVE(xp->x_drive)] = -1;
X return(X_ERROR);
X }
X break;
X case SEEK:
X status = dmardat(FDC_CS, FDC_DELAY);
X if (status & (RNF | CRCERR)) {
X curcyl[DRIVE(xp->x_drive)] = -1;
X return(X_ERROR);
X }
X return(X_AGAIN);
X case RESTORE:
X /* Determine if the recalibration succeeded. */
X status = dmardat(FDC_CS, FDC_DELAY);
X if (status & RNF) {
X printf("fd%d: recalibrate failed. status = 0x%x\n",
X xp->x_drive, status&0xFF);
X dmawdat(FDC_CS, IRUPT, FDC_DELAY); /* reset controller */
X curcyl[DRIVE(xp->x_drive)] = -1;
X return(X_ERROR);
X }
X curcyl[DRIVE(xp->x_drive)] = 0;
X return(X_AGAIN);
X default:
X ASSERT(0);
X }
X return(X_OK);
X}
X
X/*===========================================================================*
X * do_ioctl *
X *===========================================================================*/
XPRIVATE int do_ioctl(mp)
Xregister message *mp; /* pointer to read or write message */
X{
X register struct fparam *f;
X register int sector_size;
X register unsigned char nr_sectors, nr_cylinders;
X
X if (DRIVE(mp->DEVICE) >= NR_DRIVES)
X return(ENXIO);
X if (DTYPE(mp->DEVICE) >= NR_TYPES)
X return(ENXIO);
X
X f = fparam + (DTYPE(mp->DEVICE)<<1) + DRIVE(mp->DEVICE);
X switch(mp->COUNT)
X {
X case DIOCGETP:
X mp->POSITION = ((long)f->sector_size << 16) | (f->nr_sectors << 8) | f->nr_cylinders;
X break;
X
X case DIOCSETP:
X if (DTYPE(mp->DEVICE) & FORMAT)
X return(ENXIO);
X sector_size = mp->POSITION >> 16;
X nr_sectors = (mp->POSITION >> 8) & BYTE;
X nr_cylinders = mp->POSITION & BYTE;
X if (sector_size != 512 && sector_size != 1024 &&
X sector_size != 2048 && sector_size != 4096)
X return(EINVAL);
X if (nr_sectors * sector_size > 7186)
X return(EINVAL);
X if (!(DTYPE(mp->DEVICE) & DENSE)
X && nr_sectors * sector_size > 5120)
X return(EINVAL);
X if (nr_cylinders >84)
X return(EINVAL);
X f->sector_size = sector_size;
X f->nr_sectors = nr_sectors;
X f->nr_cylinders = nr_cylinders;
X f += (FORMAT << 1);
X f->nr_cylinders = nr_cylinders;
X break;
X
X default:
X return(EINVAL);
X }
X return(0);
X}
X#endif
/
echo x - stsound.cdif
sed '/^X/s///' > stsound.cdif << '/'
X*** stsound.h.1.5 Mon Mar 12 16:53:45 1990
X--- stsound.h Mon Mar 12 16:55:15 1990
X***************
X*** 62,65 ****
X #define PA_SDTR 0x10 /* Serial DTR */
X #define PA_PSTROBE 0x20 /* Parallel Strobe */
X #define PA_USER 0x40 /* Free Pin on Monitor Connector */
X! /* 0x80 /* reserved */
X--- 62,65 ----
X #define PA_SDTR 0x10 /* Serial DTR */
X #define PA_PSTROBE 0x20 /* Parallel Strobe */
X #define PA_USER 0x40 /* Free Pin on Monitor Connector */
X! #define PA_FDDENS 0x80 /* select floppy disk density */
/leo@marco.UUCP (Matthias Pfaller) (03/13/90)
sorry, i forgot to post the patch for sgtty.h
leo@marco.UUCP (Matthias Pfaller)
*** sgtty.h.1.5 Mon Mar 12 17:12:26 1990
--- sgtty.h Mon Mar 12 17:11:46 1990
***************
*** 34,40 ****
--- 34,43 ----
#define CBREAK 0000002 /* enable cbreak mode */
#define COOKED 0000000 /* neither CBREAK nor RAW */
+ #define DCD 010000 /* Data Carrier Detect */
+
/* Line speeds */
+ #define B0 0 /* code for line-hangup */
#define B110 1
#define B300 3
#define B1200 12
***************
*** 83,88 ****
--- 86,102 ----
#define DC_RICD (DCLOCK|4)
#define DC_WBMS100 (DCLOCK|8)
#define DC_WBMS200 (DCLOCK|9)
+
+ /* Data structures for disk ioctl */
+
+ struct fd_ioctl {
+ int sector_size; /* sector size in bytes */
+ char nr_sectors; /* sectors per track */
+ char nr_cylinders; /* number of cylinders */
+ };
+
+ #define DIOCGETP (('d'<<8)|8)
+ #define DIOCSETP (('d'<<8)|9)
#endif
#include <ansi.h>leo@marco.UUCP (Matthias Pfaller) (03/16/90)
please change the definition of fd_ioctl in sgtty.h from
struct fd_ioctl {
int sector_size; /* sector size in bytes */
char nr_sectors; /* sectors per track */
char nr_cylinders; /* number of cylinders */
};
to
struct fd_ioctl {
int sector_size; /* sector size in bytes */
char nr_sectors; /* sectors per track */
char nr_cylinders; /* number of cylinders */
int filler;
};
The formatter will not work without this change.
leo@marco.UUCP (Matthias Pfaller)