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)