Mail Archives: djgpp/1994/11/23/16:46:16
>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(¶m_info);
param_segment = 0;
}
static void alloc_param_buffer()
{
if (param_segment) return;
param_info.size = 1;
if (_go32_dpmi_allocate_dos_memory(¶m_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 -