From: Paul Koning 1695 To: djgpp mailing list 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 #include #include #include #include #include #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); } }