/*
   Pcm: a PC eMulator
   Copyright (C) 1992 Electronetics, Inc.  All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * Machine dependent code
 */

#include "sim.h"
#include <errno.h>
/*
 * Floppy formatting code for sparcstation
 * Assumes device has already been opened.
 */
#ifdef sun

#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <sun/dkio.h>
#include <sun/dklabel.h>

int chng_stat;
extern char *sys_errlist[];
struct fdk_char flp_char = {
  0,    /* medium */
  250,  /* transfer rate */
  80,   /* no. of tracks */
  2,    /* no. of heads  */
  512,  /* sec. size in bytes */
  9,    /* sectors/track */
  -1    /* steps? */
};

floppy_setup(dnum)
int dnum; {
  int flp_fd;
  flp_fd = disk[dnum].fd;
  if (ioctl(flp_fd, FDKIOGCHAR, &flp_char)) {
    fprintf(stderr,"Can't get floppy drive parameters: %s\n",
      sys_errlist[errno]);
    return 1;
  }
  if (disk[dnum].tracks != 80) {
    return 1;
  }
  if (disk[dnum].sectors == 9) {
    flp_char.transfer_rate = 250;
    flp_char.secptrack = 9;
  }
  else if (disk[dnum].sectors == 18) {
    flp_char.transfer_rate = 500;
    flp_char.secptrack = 18;
  }
  else {
    return 1;
  }
/*
 * Set the new characteristics
 */
  if (ioctl(flp_fd, FDKIOSCHAR, &flp_char)) {
    fprintf(stderr,"Can't set floppy drive parameters: %s\n",
      sys_errlist[errno]);
    return 1;
  }
  return 0; 
}

#ifdef sparc
#include <alloca.h>
#endif

struct fdraw seek_cmd = {
  { FRAW_SEEK },  /* fr_cmd[] */
  3               /* fr_cnum  */
};
struct fdraw fmt_cmd = {
  { 0x40 | FRAW_FORMAT, 0, 2, 0, 0x54, 0xe5 },
  6
};
/*
 * This formats all the numsecs sectors on the given track
 */
floppy_format(numsecs, track, sector, head, drive, bufaddr)
unsigned int numsecs, track, sector, head, drive;
unsigned char *bufaddr; {
  int flp_fd, i;
  char *fmt_buf, *buf_ptr;
  flp_fd = disk[drive].fd;
/*  printf("%d secs. track %d sector %d head %d drive %d\n",
    numsecs, track,sector,head,drive); */
  fmt_buf = (char *)alloca(numsecs << 2);
  seek_cmd.fr_cmd[2] = track;
  if (ioctl(flp_fd, F_RAW, &seek_cmd)) return 1;
  buf_ptr = fmt_buf;
  for (i = 1; i <= numsecs; i++) {
    *buf_ptr++ = track;
    *buf_ptr++ = head;
    *buf_ptr++ = i;
    *buf_ptr++ = 2;  /* Hard code 512 byte sector size */
  }  
  fmt_cmd.fr_cmd[1] = head << 2;
  fmt_cmd.fr_cmd[3] = flp_char.secptrack;
  fmt_cmd.fr_nbytes = flp_char.secptrack << 2;
  fmt_cmd.fr_addr   = fmt_buf;
  if (ioctl(flp_fd, F_RAW, &fmt_cmd)) return 1;
  return 0;
}
/*
 * Verifies numsecs sectors on track starting at
 * the *first* sector
 */
char *vbuf1;
unsigned int buf_size;

floppy_verify(numsecs, track, sector, head, drive)
unsigned int numsecs, track, sector, head, drive; {
  int flp_fd;
  unsigned int offset;
  char *vbuf2;

  flp_fd = disk[drive].fd;
  if (buf_size != numsecs * flp_char.sec_size) {
    if (vbuf1) free(vbuf1);
    vbuf1 = (char *)malloc(buf_size = numsecs * flp_char.sec_size);
    if (!vbuf1) {
      fprintf(stderr,"error: malloc failure %d bytes\n",buf_size);
      exit(1);
    }
    memset(vbuf1, 0xa5, buf_size);
  }
  vbuf2 = (char *)alloca(buf_size);
  offset = flp_char.secptrack * track;
  if (lseek(flp_fd, offset, 0) != offset) return 1;
  if (write(flp_fd, vbuf1, buf_size) != buf_size) return 1;
  if (lseek(flp_fd, offset, 0) != offset) return 1;
  if (read(flp_fd, vbuf2, buf_size) != buf_size) return 1;
  if (memcmp(vbuf1, vbuf2, buf_size)) return 1;
  return 0;
}

floppy_in_drive_p(flp_fd)
int flp_fd; {
  if (ioctl(flp_fd, FDKGETCHANGE, &chng_stat) == 0) {
    if (chng_stat & FDKGC_CURRENT)
      return 0;
  }
  return 1;
}

floppy_eject() {
  int i;
  for (i = 0; i < numdrives; i++) {
    if (disk[i].devicep) {
      ioctl(disk[i].fd, FDKEJECT);
    }
  }
}

#endif /* sun */
