Logo Search packages:      
Sourcecode: acorn-fdisk version File versions  Download package

open.c

/*
 * blkio/open.c
 *
 * Copyright (C) 1998 Russell King
 *
 * The block I/O interface allows an OS-independent method to access devices
 *
 * Open a device on RiscOS architecture
 */
#include <assert.h>
#include <string.h>
#include <stdlib.h>

#include "util/debug.h"
#include "util/error.h"
#include "util/zmalloc.h"

#include "blkio.h"
#include "filecore.h"

#define MAX_FS_NAME     10
#define MAX_DRIVE_NAME  20

#ifdef RISCOS
#include "!Swi.h"
#include "util/swi_num.h"

struct ide_identify_request {
  unsigned long unused;
  unsigned char unused1;
  unsigned char length;
  unsigned char cmd;
  unsigned char unused2;
};

struct ide_identify_result {
  unsigned short config;
  unsigned short cyls;
  unsigned short reserved2;
  unsigned short heads;
  unsigned short track_bytes;
  unsigned short sector_bytes;
  unsigned short sectors;
  unsigned short vendor0;
  unsigned short vendor1;
  unsigned short vendor2;
  unsigned char  serial_no[20];
  unsigned short buf_type;
  unsigned short buf_size;
  unsigned short ecc_bytes;
  unsigned char  fw_rev[8];
  unsigned char  model[40];
  unsigned char  max_multsect;
  unsigned char  vendor3;
  unsigned short dword_io;
  unsigned char  vendor4;
  unsigned char  capability;  /* 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup */
  unsigned short reserved50;
  unsigned char  vendor5;
  unsigned char  tPIO;        /* 0 slow 1 medium 2 fast */
  unsigned char  vendor6;
  unsigned char  tDMA;        /* 0 slow 1 medium 2 fast */
  unsigned short field_valid; /* 0:cur_ok 1:eideok */
  unsigned short cur_cyls;
  unsigned short cur_heads;
  unsigned short cur_sectors;
  unsigned short cur_capacity0;
  unsigned char  multsect;
  unsigned char  multsect_valid;
  unsigned int   lba_capacity;
  unsigned short dma_1word;
  unsigned short dma_mword;
  unsigned short eide_pio_modes;/* 0:mode3 1:mode4 */
  unsigned short eide_dma_min;      /* min mword dma cycle time */
  unsigned short eide_dma_time; /* recommended */
  unsigned short eide_pio;    /* min cycle time */
  unsigned short eide_pio_iordy;/* min cycle time with IORDY (ns) */
  unsigned short reserved69;
  unsigned short reserved70;
  unsigned short reservedxx[256-71];
};

#define TYPE_NOTPRESENT 0
#define TYPE_FD1772     1
#define TYPE_8271x      2
#define TYPE_ST506      3
#define TYPE_IDE  4
#define TYPE_SCSI (256+4)

/* Function: int split_fs_name (const char *dev_name, char *fs_name, char *drive_name)
 * Purpose : Split a device name into fs name and drive name
 * Params  : dev_name   - device name to split
 *         : fs_name    - pointer to filesystem name
 *         : drive_name - pointer to drive name
 * Returns : TRUE if successful, fs_name & drive_name containing strings
 */
static int split_fs_name (const char *dev_name, char *fs_name, char *drive_name)
{
  const char *p;
  int error = 1;
  enum {
    s_in_fs, s_drv, s_in_drv, s_finished
  } state;

  state = s_in_fs;

  for (p = dev_name; state != s_finished; p ++) {
    switch (state) {
    case s_in_fs:
      if (*p != ':' && *p != '\0')
        *fs_name++ = *p;
      else {
        *fs_name = '\0';
        if (*p == '\0')
          state = s_finished;
        else
          state = s_drv;
      }
      break;

    case s_drv:
      if (*p == ':')
        state = s_in_drv;
      else
        state = s_finished;
      break;

    case s_in_drv:
      if (*p != '.' && *p != '\0')
        *drive_name++ = *p;
      else {
        *drive_name = '\0';
        state = s_finished;
        error = 0;
      }
      break;
    }
  }
  *fs_name = '\0';
  *drive_name = '\0';
  return !error;
}

static void set_disc_geometry (blkio_t *blkio, geometry_t *geo)
{
  u_int log2secsize, sectors, update_disc_record = 0;

  log2secsize = blkio->disc_record->d.log2secsize;
  sectors          = (blkio->disc_record->d.disc_size_high << (32 - log2secsize)) |
                 (blkio->disc_record->d.disc_size >> log2secsize);

  geo->sector_size = 1 << log2secsize;
  geo->log2secsize = log2secsize;
  geo->sectors     = blkio->disc_record->d.secspertrack;
  geo->heads       = blkio->disc_record->d.heads +
                 (blkio->disc_record->d.lowsector & 0x40 ? 1 : 0);
  geo->cylinders   = sectors / (geo->heads * geo->sectors);

  if (blkio->swi_ideuserop) {
    struct ide_identify_request ide_id_req;
    struct ide_identify_result ide_id_res;
    int slave = 0, type;

    if (blkio->swi_controllertype) {
      if (!swix (blkio->swi_controllertype, rin(r0)|rout(r0), blkio->drive, &type) &&
          type == TYPE_IDE &&
          !swix(blkio->swi_controllertype, rin(r0)|rout(r0), blkio->drive - 1, &type) &&
          type == TYPE_IDE)
        slave = 1;
    }

    dbg_printf ("-IDE drive is a %s", slave ? "slave" : "master");

    memset (&ide_id_req, 0, sizeof (ide_id_req));
    ide_id_req.length = 160 | (slave ? 1 << 4 : 0);
    ide_id_req.cmd = 236;
    if (!swix (blkio->swi_ideuserop, rin(r0|r2|r3|r4),
               1 << 24, &ide_id_req, &ide_id_res, 512)) {
      geo->log2secsize = 9;
      geo->sector_size = 1 << 9;
      geo->sectors   = ide_id_res.sectors;
      geo->heads     = ide_id_res.heads;
      geo->cylinders = ide_id_res.cyls;
      update_disc_record = 1;
    }
  } else if (geo->sectors == 1) {
    geo->log2secsize = 9;
    geo->sector_size = 1 << 9;
    geo->sectors = 17;
    geo->heads = 1;
    geo->cylinders = 0;
    update_disc_record = 1;
  }
  if (update_disc_record
#if 0
       && (geo->sector_size == 1 << log2secsize) &&
      (geo->sectors     == blkio->disc_record->d.secspertrack) &&
      (geo->heads       == blkio->disc_record->d.heads +
                           (blkio->disc_record->d.lowsector & 0x40 ? 1 : 0))
#endif
    ) {
    sectors = geo->cylinders * geo->heads * geo->sectors;
    if (sectors >= (512 * 1024 * 1024 >> log2secsize))
      blkio->disc_record->d.big_flag = 1;
    blkio->disc_record->d.log2secsize = geo->log2secsize;
    blkio->disc_record->d.secspertrack = geo->sectors;
    blkio->disc_record->d.heads = geo->heads - (blkio->disc_record->d.lowsector & 0x40 ? 1 : 0);
    blkio->disc_record->d.disc_size_high = sectors >> (32 - log2secsize);
    blkio->disc_record->d.disc_size = sectors << log2secsize;
  }
  dbg_printf("-geometry: [secsz=%d, sec/tk=%d, hds=%d, cyls=%d]",
           geo->sector_size, geo->sectors, geo->heads, geo->cylinders);
}

/* Function: blkio_t *blkio_open (const char *dev_name)
 * Purpose : Open a device, specified in dev_name and return a structure
 * Params  : dev_name - device name (eg, ADFS::4, /dev/hda etc)
 * Returns : pointer to above structure (to be used by all other calls)
 */
blkio_t *blkio_open (const char *dev_name)
{
  /* On RiscOS, dev_name is something like 'ADFS::4....' */
  blkio_t *blkio = NULL;
  char fs_name[MAX_FS_NAME], drive_name[MAX_DRIVE_NAME];

  assert (dev_name != NULL);
  assert (sizeof (union disc_record) >= 64);

  dbg_printf ("blkio_open(%s)", dev_name);
  dbg_level_up ();

  do {
    if (!split_fs_name (dev_name, fs_name, drive_name)) {
      set_error ("Invalid filesystem name `%s'", dev_name);
      break;
    }

    dbg_printf ("-filesystem '%s' drive '%s'", fs_name, drive_name);

    blkio = zmalloc (sizeof (blkio_t));
    if (blkio == NULL)
      break;

    blkio->swi_describedisc = swi_number (fs_name, "DescribeDisc");
    blkio->swi_discop = swi_number (fs_name, "DiscOp");
    blkio->swi_sectorop = swi_number (fs_name, "SectorOp");
    if (blkio->swi_sectorop == 0)
      blkio->swi_sectorop = swi_number (fs_name, "SectorDiscOp");
    blkio->swi_controllertype = swi_number (fs_name, "ControllerType");
    blkio->swi_ideuserop = swi_number (fs_name, "IDEUserOp");

    dbg_printf ("-swis: DescribeDisc 0x%05X, DiscOp 0x%05X, SectorOp 0x%05X",
            blkio->swi_describedisc, blkio->swi_discop, blkio->swi_sectorop);
    dbg_printf ("-swis: ControllerType 0x%05X, IDEUserOp 0x%05X",
            blkio->swi_controllertype, blkio->swi_ideuserop);

    if (blkio->swi_describedisc == 0) {
      set_error ("Bad filesystem type name `%s'", fs_name);
      free (blkio);
      blkio = NULL;
      break;
    }

    blkio->disc_record = zmalloc (sizeof (union disc_record));
    if (!blkio->disc_record) {
      free (blkio);
      blkio = NULL;
      break;
    }

    if (swix (blkio->swi_describedisc, rin(r0|r1), drive_name, blkio->disc_record)) {
      set_error ("Invalid filesystem drive name `%s'", drive_name);
      free (blkio->disc_record);
      free (blkio);
      blkio = NULL;
      break;
    }

    blkio->drive = (blkio->disc_record->d.root >> 29) & 7;
    blkio->blocksize = 1 << blkio->disc_record->d.log2secsize;
    dbg_printf ("-disc_record: [secsz=%d, sec/tk=%d, hds=%d, ds=0x%08X%08X%s drv=%d]",
              blkio->blocksize,
              blkio->disc_record->d.secspertrack,
              blkio->disc_record->d.heads,
              blkio->disc_record->d.disc_size_high, blkio->disc_record->d.disc_size,
              blkio->disc_record->d.big_flag ? " big" : "",
              blkio->drive);

    set_disc_geometry (blkio, &blkio->geometry);
    dbg_printf ("-new disc record: [secsz=%d, sec/tk=%d, hds=%d, ds=0x%08X%08X%s drv=%d]",
              blkio->blocksize,
              blkio->disc_record->d.secspertrack,
              blkio->disc_record->d.heads,
              blkio->disc_record->d.disc_size_high, blkio->disc_record->d.disc_size,
              blkio->disc_record->d.big_flag ? " big" : "",
              blkio->drive);
  } while (0);

  dbg_level_down();
  dbg_printf ("ret=%p", blkio);
  return blkio;
}
#endif

#ifdef UNIX
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>

#ifdef linux
#include <linux/hdreg.h>
#endif

/* Function: blkio_t *blkio_open (const char *dev_name)
 * Purpose : Open a device, specified in dev_name and return a structure
 * Params  : dev_name - device name (eg, ADFS::4, /dev/hda etc)
 * Returns : pointer to above structure (to be used by all other calls)
 */
blkio_t *blkio_open (const char *dev_name)
{
  /* On RiscOS, dev_name is something like 'ADFS::4....' */
  blkio_t *blkio = NULL;

  assert (dev_name != NULL);
  assert (sizeof (union disc_record) >= 64);

  dbg_printf ("blkio_open(%s)", dev_name);
  dbg_level_up ();

  do {
    struct hd_geometry geometry;

    blkio = zmalloc (sizeof (blkio_t));
    if (blkio == NULL)
      break;

    blkio->fd = open(dev_name, O_RDWR);
    if (blkio->fd == (u_int)-1)
      blkio->fd = open(dev_name, O_RDONLY);

    if (blkio->fd == (u_int)-1) {
      set_error ("%s", strerror(errno));
      free(blkio);
      blkio = NULL;
      break;
    }
    
    if (!ioctl(blkio->fd, HDIO_GETGEO, &geometry)) {
      blkio->geometry.cylinders = geometry.cylinders;
      blkio->geometry.heads = geometry.heads;
      blkio->geometry.sectors = geometry.sectors;
      blkio->geometry.sector_size = 512;
      blkio->geometry.log2secsize = 9;
    } else {
      blkio->geometry.cylinders = 1024;
      blkio->geometry.heads = 16;
      blkio->geometry.sectors = 63;
      blkio->geometry.sector_size = 512;
      blkio->geometry.log2secsize = 9;
    }
    blkio->blocksize = 512;

    dbg_printf("-geometry: [secsz=%d, sec/tk=%d, hds=%d, cyls=%d]",
            blkio->geometry.sector_size,
            blkio->geometry.sectors,
            blkio->geometry.heads,
            blkio->geometry.cylinders);
  } while (0);

  dbg_level_down();
  dbg_printf ("ret=%p", blkio);
  return blkio;
}
#endif

Generated by  Doxygen 1.6.0   Back to index