www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1994/11/23/16:46:16

From: Paul Koning 1695 <pkoning AT chipcom DOT com>
To: djgpp mailing list <djgpp AT sun DOT soe DOT clarkson DOT edu>
Subject: RE: Interrupts
Date: Wed, 23 Nov 94 10:34:00 PST
Encoding: 208 TEXT

>From: djgpp-bounces
>To: djgpp
>Subject: Interrupts
>Date: Tuesday, November 22, 1994 8:14PM
>
>If I need to call an interrupt that expects a segment:offset pair to be
>in the registers, how do I do that in DJGPP?

int86() works for the interrupts it decides to support (which doesn't seem 
to be
documented).  But you can get to any interrupt you like with only a little 
more
work.  Here's a module I used to do various kinds of weird disk I/O; some of
it uses bios I/O which the djgpp library supports directly, but the rest is 
DOS
absolute I/O (int 25h, 26h) which is not supported directly.  So I did it 
the
roundabout way via _go32_dpmi_simulate_int().  You can also see how
to set up parameter buffers in DOS address space.

Thanks to DJ for helping me figure this stuff out...

     paul

/* absread and abswrite services for use with DJGPP GNU C implementation
 *
 * Paul Koning 94.10.16
 *        94.11.18  added bios i/o
 *        94.11.21  dos i/o for hard disk, bios i/o for floppy
 */

#include <bios.h>
#include <dos.h>
#include <go32.h>
#include <dpmi.h>
#include <stdio.h>
#include <stdlib.h>

#include "flx.h"
#include "dosabsio.h"

#define tb _go32_info_block.linear_address_of_transfer_buffer

#define BIOSBUF (16*BLKSIZE)  /* size of djgpp bios disk I/O buffer */
#define BIOSREAD 2       /* bios disk read function code */
#define BIOSWRITE 3      /* bios disk write function code */
#define ABSREAD     0x25      /* abs read int code */
#define ABSWRITE 0x26         /* abs write int code */

static int     secsize = 0;
static int     param_segment = 0;
static int     rxflag = 0;    /* set if accessing 5.25 inch floppy */
static int     gdrive = -1;   /* drive to which geometry data applies */
static int     sectors, heads, cylinders, drives;
static _go32_dpmi_seginfo param_info;

static void free_param_buffer()
{
     _go32_dpmi_free_dos_memory(&param_info);
     param_segment = 0;
}

static void alloc_param_buffer()
{
     if (param_segment) return;
     param_info.size = 1;
     if (_go32_dpmi_allocate_dos_memory(&param_info)) {
          param_segment = 0;
          return;
     }
     param_segment = param_info.rm_segment;
     atexit(free_param_buffer);
}

/* convert dos style drive number to bios style number */

static int biosdrive (int drive)
{
     if (drive < 3) return (drive - 1);
     else return ((drive - 3) + 0x80);  /* need to do partitions */
}

static int getgeom (int drive)
{
     byte status[4];

     gdrive = drive;
     biosdisk (8, biosdrive (drive), 0, 0, 0, 1, status);
     heads = status[3] + 1;
     drives = status[2];
     cylinders = status[1] + ((status[0] >> 6) << 8) + 1;
     sectors = status[0] & 0x3f;
}

/* do bios disk I/O call */

static int biosio (int func, int drive, int dsksec, int count, void *buffer)
{
     int  track, sec, cyl;
     int  tcount, status;

     if (drive != gdrive) getgeom (drive);
     while (count) {
          tcount = count;
          if (tcount > BIOSBUF) tcount = BIOSBUF;
          sec = dsksec % sectors + 1;
          track = (dsksec / sectors) % cylinders;
          cyl = dsksec / (sectors * cylinders);
          status = biosdisk (func, biosdrive (drive), track, cyl, sec,
                 tcount / BLKSIZE, buffer);
          if (status) return (status);
          count -= tcount;
          buffer += tcount;
          dsksec += (tcount / BLKSIZE);
     }
     return (0);
}

/* do absolute dos disk read/write
 * arguments:
 *   function code (0x25 = read, 0x26 = write)
 *   drive number (1 = a:, etc)
 *   starting sector number
 *   byte count (must be multiple of sector size)
 *   buffer pointer
 */

static int dosio (int func, int drive, int sec, int count, void *buffer)
{
     int bseg, bofs, xfer=0, before=0, tcount;
     _go32_dpmi_registers     r;
     unsigned short int  param[5];

     while (count) {
          tcount = count;
          if (tcount > _go32_info_block.size_of_transfer_buffer)
              tcount = _go32_info_block.size_of_transfer_buffer;
          alloc_param_buffer();
          param[0] = sec & 0xffff;
          param[1] = sec >> 16;
          param[2] = (tcount / secsize) & 0xffff;
          param[3] = (unsigned int) tb & 15;
          param[4] = (unsigned int) tb >> 4;
          dosmemput(param, sizeof(param), param_segment << 4);
          if (func == ABSWRITE)
              dosmemput(buffer, tcount, tb);
          memset(&r, 0, sizeof(r));
          r.h.al = drive - 1;      /* 0-based numbering here */
          r.x.ds = param_segment;
          r.x.bx = 0;
          r.x.cx = -1;
          _go32_dpmi_simulate_int(func, &r);
          if (func == ABSREAD)
              dosmemget(tb, tcount, buffer);
          if (r.x.flags & 1)
              return (r.h.al);
          count -= tcount;
          buffer += tcount;
          sec += (tcount / secsize);
     }
     return (0);
}

int absread (int drive, int sec, int count, void *buffer)
{
     if (drive >= 3)          /* hard disk */
         return (absio (ABSREAD, drive, sec, count, buffer));
     else
         return (biosio (BIOSREAD, drive, sec, count, buffer));
}

int abswrite (int drive, int sec, int count, void *buffer)
{
#ifdef NOT_YET
     if (drive >= 3)          /* hard disk */
         return (absio (ABSWRITE, drive, sec, count, buffer));
     else
         return (biosio (BIOSWRITE, drive, sec, count, buffer));
#endif
}

/* return size of specified disk, in blocks.  Saves sector size in a local
 * static variable as a side effect.  A flag is set if the disk is a
 * 5.25 inch floppy.
 * Note: this must be called before any abs I/O is done.
 */

int disksize (int drive)
{
     _go32_dpmi_registers     r;
     byte           mid;

     memset(&r, 0, sizeof(r));
     r.h.ah = 0x1c;
     r.h.dl = drive;
     _go32_dpmi_simulate_int(0x21, &r);
     dosmemget((r.x.ds << 4) + r.x.bx, 1, &mid);
     rxflag = (mid >= 0xf9);       /* flag if 5.25 inch floppy */
     if (drive >= 3) {        /* hard disk */
          secsize = r.x.cx;
          return (r.h.al * r.x.dx * secsize / BLKSIZE);
     } else {
          getgeom (drive);
          secsize = 512;
          return (cylinders * heads * sectors);
     }
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019