|
|
|
@ -1,527 +0,0 @@
|
|
|
|
|
/* This file contains the "device dependent" part of a hard disk driver that
|
|
|
|
|
* uses the ROM BIOS. It makes a call and just waits for the transfer to
|
|
|
|
|
* happen. It is not interrupt driven and thus will (*) have poor performance.
|
|
|
|
|
* The advantage is that it should work on virtually any PC, XT, 386, PS/2
|
|
|
|
|
* or clone. The demo disk uses this driver. It is suggested that all
|
|
|
|
|
* MINIX users try the other drivers, and use this one only as a last resort,
|
|
|
|
|
* if all else fails.
|
|
|
|
|
*
|
|
|
|
|
* (*) The performance is within 10% of the AT driver for reads on any disk
|
|
|
|
|
* and writes on a 2:1 interleaved disk, it will be DMA_BUF_SIZE bytes
|
|
|
|
|
* per revolution for a minimum of 60 kb/s for writes to 1:1 disks.
|
|
|
|
|
*
|
|
|
|
|
* The file contains one entry point:
|
|
|
|
|
*
|
|
|
|
|
* bios_winchester_task: main entry when system is brought up
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Changes:
|
|
|
|
|
* 30 Apr 1992 by Kees J. Bot: device dependent/independent split.
|
|
|
|
|
* 14 May 2000 by Kees J. Bot: d-d/i rewrite.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <minix/drivers.h>
|
|
|
|
|
#include <minix/blockdriver.h>
|
|
|
|
|
#include <minix/drvlib.h>
|
|
|
|
|
#include <minix/sysutil.h>
|
|
|
|
|
#include <minix/safecopies.h>
|
|
|
|
|
#include <sys/ioc_disk.h>
|
|
|
|
|
#include <machine/int86.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
/* Parameters for the disk drive. */
|
|
|
|
|
#define MAX_DRIVES 8 /* this driver supports 8 drives (d0 - d7)*/
|
|
|
|
|
#define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE)
|
|
|
|
|
#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
|
|
|
|
|
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
|
|
|
|
|
|
|
|
|
|
/* Variables. */
|
|
|
|
|
static struct wini { /* main drive struct, one entry per drive */
|
|
|
|
|
unsigned cylinders; /* number of cylinders */
|
|
|
|
|
unsigned heads; /* number of heads */
|
|
|
|
|
unsigned sectors; /* number of sectors per track */
|
|
|
|
|
unsigned open_ct; /* in-use count */
|
|
|
|
|
int drive_id; /* Drive ID at BIOS level */
|
|
|
|
|
int present; /* Valid drive */
|
|
|
|
|
int int13ext; /* IBM/MS INT 13 extensions supported? */
|
|
|
|
|
struct device part[DEV_PER_DRIVE]; /* disks and partitions */
|
|
|
|
|
struct device subpart[SUB_PER_DRIVE]; /* subpartitions */
|
|
|
|
|
} wini[MAX_DRIVES], *w_wn;
|
|
|
|
|
|
|
|
|
|
static int w_drive; /* selected drive */
|
|
|
|
|
static struct device *w_dv; /* device's base and size */
|
|
|
|
|
static char *bios_buf_v;
|
|
|
|
|
static phys_bytes bios_buf_phys;
|
|
|
|
|
static int remap_first = 0; /* Remap drives for CD HD emulation */
|
|
|
|
|
#define BIOSBUF 16384
|
|
|
|
|
|
|
|
|
|
int main(void);
|
|
|
|
|
static struct device *w_prepare(dev_t device);
|
|
|
|
|
static struct device *w_part(dev_t minor);
|
|
|
|
|
static ssize_t w_transfer(dev_t minor, int do_write, u64_t position,
|
|
|
|
|
endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags);
|
|
|
|
|
static int w_do_open(dev_t minor, int access);
|
|
|
|
|
static int w_do_close(dev_t minor);
|
|
|
|
|
static void w_init(void);
|
|
|
|
|
static void w_geometry(dev_t minor, struct partition *entry);
|
|
|
|
|
static int w_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
|
|
|
|
|
cp_grant_id_t grant);
|
|
|
|
|
|
|
|
|
|
/* Entry points to this driver. */
|
|
|
|
|
static struct blockdriver w_dtab = {
|
|
|
|
|
BLOCKDRIVER_TYPE_DISK, /* handle partition requests */
|
|
|
|
|
w_do_open, /* open or mount request, initialize device */
|
|
|
|
|
w_do_close, /* release device */
|
|
|
|
|
w_transfer, /* do the I/O */
|
|
|
|
|
w_ioctl, /* I/O control */
|
|
|
|
|
NULL, /* no cleanup needed */
|
|
|
|
|
w_part, /* return partition information structure */
|
|
|
|
|
w_geometry, /* tell the geometry of the disk */
|
|
|
|
|
NULL, /* leftover hardware interrupts */
|
|
|
|
|
NULL, /* ignore leftover alarms */
|
|
|
|
|
NULL, /* catch-all for unrecognized commands */
|
|
|
|
|
NULL /* no threading support */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* SEF functions and variables. */
|
|
|
|
|
static void sef_local_startup(void);
|
|
|
|
|
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* bios_winchester_task *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
/* SEF local startup. */
|
|
|
|
|
sef_local_startup();
|
|
|
|
|
|
|
|
|
|
/* Call the generic receive loop. */
|
|
|
|
|
blockdriver_task(&w_dtab);
|
|
|
|
|
|
|
|
|
|
return(OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* sef_local_startup *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static void sef_local_startup(void)
|
|
|
|
|
{
|
|
|
|
|
/* Register init callbacks. */
|
|
|
|
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
|
|
|
sef_setcb_init_lu(sef_cb_init_fresh);
|
|
|
|
|
|
|
|
|
|
/* Register live update callbacks. */
|
|
|
|
|
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
|
|
|
|
|
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
|
|
|
|
|
|
|
|
|
|
/* Let SEF perform startup. */
|
|
|
|
|
sef_startup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* sef_cb_init_fresh *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
|
|
|
|
|
{
|
|
|
|
|
/* Initialize the bios_wini driver. */
|
|
|
|
|
long v;
|
|
|
|
|
|
|
|
|
|
v = 0;
|
|
|
|
|
env_parse("bios_remap_first", "d", 0, &v, 0, 1);
|
|
|
|
|
remap_first = v;
|
|
|
|
|
|
|
|
|
|
/* Announce we are up! */
|
|
|
|
|
blockdriver_announce(type);
|
|
|
|
|
|
|
|
|
|
return(OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* w_prepare *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static struct device *w_prepare(dev_t device)
|
|
|
|
|
{
|
|
|
|
|
/* Prepare for I/O on a device. */
|
|
|
|
|
|
|
|
|
|
if (device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */
|
|
|
|
|
w_drive = device / DEV_PER_DRIVE; /* save drive number */
|
|
|
|
|
w_wn = &wini[w_drive];
|
|
|
|
|
w_dv = &w_wn->part[device % DEV_PER_DRIVE];
|
|
|
|
|
} else
|
|
|
|
|
if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
|
|
|
|
|
w_drive = device / SUB_PER_DRIVE;
|
|
|
|
|
w_wn = &wini[w_drive];
|
|
|
|
|
w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
|
|
|
|
|
} else {
|
|
|
|
|
return(NULL);
|
|
|
|
|
}
|
|
|
|
|
if (w_drive >= MAX_DRIVES || !w_wn->present)
|
|
|
|
|
return NULL;
|
|
|
|
|
return(w_dv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* w_part *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static struct device *w_part(dev_t minor)
|
|
|
|
|
{
|
|
|
|
|
/* Return a pointer to the partition information of the given minor device. */
|
|
|
|
|
|
|
|
|
|
return w_prepare(minor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* w_transfer *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static ssize_t w_transfer(
|
|
|
|
|
dev_t minor, /* minor device number */
|
|
|
|
|
int do_write, /* read or write? */
|
|
|
|
|
u64_t pos64, /* offset on device to read or write */
|
|
|
|
|
endpoint_t proc_nr, /* process doing the request */
|
|
|
|
|
iovec_t *iov, /* pointer to read or write request vector */
|
|
|
|
|
unsigned int nr_req, /* length of request vector */
|
|
|
|
|
int UNUSED(flags) /* transfer flags */
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
struct wini *wn;
|
|
|
|
|
iovec_t *iop, *iov_end = iov + nr_req;
|
|
|
|
|
int r, errors;
|
|
|
|
|
unsigned count;
|
|
|
|
|
vir_bytes chunk, nbytes;
|
|
|
|
|
unsigned long block;
|
|
|
|
|
vir_bytes i13e_rw_off, rem_buf_size;
|
|
|
|
|
unsigned secspcyl;
|
|
|
|
|
struct int13ext_rw {
|
|
|
|
|
u8_t len;
|
|
|
|
|
u8_t res1;
|
|
|
|
|
u16_t count;
|
|
|
|
|
u16_t addr[2];
|
|
|
|
|
u32_t block[2];
|
|
|
|
|
} *i13e_rw;
|
|
|
|
|
struct reg86u reg86;
|
|
|
|
|
u32_t lopos;
|
|
|
|
|
ssize_t total;
|
|
|
|
|
|
|
|
|
|
if (w_prepare(minor) == NULL) return(ENXIO);
|
|
|
|
|
|
|
|
|
|
wn = w_wn;
|
|
|
|
|
secspcyl = wn->heads * wn->sectors;
|
|
|
|
|
|
|
|
|
|
lopos= ex64lo(pos64);
|
|
|
|
|
|
|
|
|
|
/* Check disk address. */
|
|
|
|
|
if ((lopos & SECTOR_MASK) != 0) return(EINVAL);
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
errors = 0;
|
|
|
|
|
|
|
|
|
|
i13e_rw_off= BIOSBUF-sizeof(*i13e_rw);
|
|
|
|
|
rem_buf_size= (i13e_rw_off & ~SECTOR_MASK);
|
|
|
|
|
i13e_rw = (struct int13ext_rw *) (bios_buf_v + i13e_rw_off);
|
|
|
|
|
assert(rem_buf_size != 0);
|
|
|
|
|
|
|
|
|
|
while (nr_req > 0) {
|
|
|
|
|
/* How many bytes to transfer? */
|
|
|
|
|
nbytes = 0;
|
|
|
|
|
for (iop = iov; iop < iov_end; iop++) {
|
|
|
|
|
if (nbytes + iop->iov_size > rem_buf_size) {
|
|
|
|
|
/* Don't do half a segment if you can avoid it. */
|
|
|
|
|
if (nbytes == 0) nbytes = rem_buf_size;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
nbytes += iop->iov_size;
|
|
|
|
|
}
|
|
|
|
|
if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
|
|
|
|
|
|
|
|
|
|
/* Which block on disk and how close to EOF? */
|
|
|
|
|
if (cmp64(pos64, w_dv->dv_size) >= 0) return(total); /* At EOF */
|
|
|
|
|
if (cmp64(add64u(pos64, nbytes), w_dv->dv_size) > 0) {
|
|
|
|
|
u64_t n;
|
|
|
|
|
n = sub64(w_dv->dv_size, pos64);
|
|
|
|
|
assert(ex64hi(n) == 0);
|
|
|
|
|
nbytes = ex64lo(n);
|
|
|
|
|
}
|
|
|
|
|
block = div64u(add64(w_dv->dv_base, pos64), SECTOR_SIZE);
|
|
|
|
|
|
|
|
|
|
/* Degrade to per-sector mode if there were errors. */
|
|
|
|
|
if (errors > 0) nbytes = SECTOR_SIZE;
|
|
|
|
|
|
|
|
|
|
if (do_write) {
|
|
|
|
|
/* Copy from user space to the DMA buffer. */
|
|
|
|
|
count = 0;
|
|
|
|
|
for (iop = iov; count < nbytes; iop++) {
|
|
|
|
|
chunk = iop->iov_size;
|
|
|
|
|
if (count + chunk > nbytes) chunk = nbytes - count;
|
|
|
|
|
assert(chunk <= rem_buf_size);
|
|
|
|
|
|
|
|
|
|
if(proc_nr != SELF) {
|
|
|
|
|
r=sys_safecopyfrom(proc_nr,
|
|
|
|
|
(cp_grant_id_t) iop->iov_addr,
|
|
|
|
|
0, (vir_bytes) (bios_buf_v+count),
|
|
|
|
|
chunk, D);
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("copy failed: %d", r);
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(bios_buf_v+count,
|
|
|
|
|
(char *) iop->iov_addr, chunk);
|
|
|
|
|
}
|
|
|
|
|
count += chunk;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Do the transfer */
|
|
|
|
|
if (wn->int13ext) {
|
|
|
|
|
i13e_rw->len = 0x10;
|
|
|
|
|
i13e_rw->res1 = 0;
|
|
|
|
|
i13e_rw->count = nbytes >> SECTOR_SHIFT;
|
|
|
|
|
i13e_rw->addr[0] = bios_buf_phys % HCLICK_SIZE;
|
|
|
|
|
i13e_rw->addr[1] = bios_buf_phys / HCLICK_SIZE;
|
|
|
|
|
i13e_rw->block[0] = block;
|
|
|
|
|
i13e_rw->block[1] = 0;
|
|
|
|
|
|
|
|
|
|
/* Set up an extended read or write BIOS call. */
|
|
|
|
|
reg86.u.b.intno = 0x13;
|
|
|
|
|
reg86.u.w.ax = do_write ? 0x4300 : 0x4200;
|
|
|
|
|
reg86.u.b.dl = wn->drive_id;
|
|
|
|
|
reg86.u.w.si = (bios_buf_phys + i13e_rw_off) % HCLICK_SIZE;
|
|
|
|
|
reg86.u.w.ds = (bios_buf_phys + i13e_rw_off) / HCLICK_SIZE;
|
|
|
|
|
} else {
|
|
|
|
|
/* Set up an ordinary read or write BIOS call. */
|
|
|
|
|
unsigned cylinder = block / secspcyl;
|
|
|
|
|
unsigned sector = (block % wn->sectors) + 1;
|
|
|
|
|
unsigned head = (block % secspcyl) / wn->sectors;
|
|
|
|
|
|
|
|
|
|
reg86.u.b.intno = 0x13;
|
|
|
|
|
reg86.u.b.ah = do_write ? 0x03 : 0x02;
|
|
|
|
|
reg86.u.b.al = nbytes >> SECTOR_SHIFT;
|
|
|
|
|
reg86.u.w.bx = bios_buf_phys % HCLICK_SIZE;
|
|
|
|
|
reg86.u.w.es = bios_buf_phys / HCLICK_SIZE;
|
|
|
|
|
reg86.u.b.ch = cylinder & 0xFF;
|
|
|
|
|
reg86.u.b.cl = sector | ((cylinder & 0x300) >> 2);
|
|
|
|
|
reg86.u.b.dh = head;
|
|
|
|
|
reg86.u.b.dl = wn->drive_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r= sys_int86(®86);
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("BIOS call failed: %d", r);
|
|
|
|
|
|
|
|
|
|
if (reg86.u.w.f & 0x0001) {
|
|
|
|
|
/* An error occurred, try again sector by sector unless */
|
|
|
|
|
if (++errors == 2) return(EIO);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!do_write) {
|
|
|
|
|
/* Copy from the DMA buffer to user space. */
|
|
|
|
|
count = 0;
|
|
|
|
|
for (iop = iov; count < nbytes; iop++) {
|
|
|
|
|
chunk = iop->iov_size;
|
|
|
|
|
if (count + chunk > nbytes) chunk = nbytes - count;
|
|
|
|
|
assert(chunk <= rem_buf_size);
|
|
|
|
|
|
|
|
|
|
if(proc_nr != SELF) {
|
|
|
|
|
r=sys_safecopyto(proc_nr, iop->iov_addr,
|
|
|
|
|
0, (vir_bytes) (bios_buf_v+count),
|
|
|
|
|
chunk, D);
|
|
|
|
|
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("sys_safecopy failed: %d", r);
|
|
|
|
|
} else {
|
|
|
|
|
memcpy((char *) iop->iov_addr,
|
|
|
|
|
bios_buf_v+count, chunk);
|
|
|
|
|
}
|
|
|
|
|
count += chunk;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Book the bytes successfully transferred. */
|
|
|
|
|
pos64 = add64ul(pos64, nbytes);
|
|
|
|
|
total += nbytes;
|
|
|
|
|
while (nbytes > 0) {
|
|
|
|
|
if (nbytes < iov->iov_size) {
|
|
|
|
|
/* Not done with this one yet. */
|
|
|
|
|
iov->iov_size -= nbytes;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
nbytes -= iov->iov_size;
|
|
|
|
|
iov->iov_size = 0;
|
|
|
|
|
iov++;
|
|
|
|
|
nr_req--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return(total);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*============================================================================*
|
|
|
|
|
* w_do_open *
|
|
|
|
|
*============================================================================*/
|
|
|
|
|
static int w_do_open(dev_t minor, int UNUSED(access))
|
|
|
|
|
{
|
|
|
|
|
/* Device open: Initialize the controller and read the partition table. */
|
|
|
|
|
|
|
|
|
|
static int init_done = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!init_done) { w_init(); init_done = TRUE; }
|
|
|
|
|
|
|
|
|
|
if (w_prepare(minor) == NULL) return(ENXIO);
|
|
|
|
|
|
|
|
|
|
if (w_wn->open_ct++ == 0) {
|
|
|
|
|
/* Partition the disk. */
|
|
|
|
|
partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, 0);
|
|
|
|
|
}
|
|
|
|
|
return(OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*============================================================================*
|
|
|
|
|
* w_do_close *
|
|
|
|
|
*============================================================================*/
|
|
|
|
|
static int w_do_close(dev_t minor)
|
|
|
|
|
{
|
|
|
|
|
/* Device close: Release a device. */
|
|
|
|
|
|
|
|
|
|
if (w_prepare(minor) == NULL) return(ENXIO);
|
|
|
|
|
w_wn->open_ct--;
|
|
|
|
|
return(OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
|
* w_init *
|
|
|
|
|
*===========================================================================*/
|
|
|
|
|
static void w_init(void)
|
|
|
|
|
{
|
|
|
|
|
/* This routine is called at startup to initialize the drive parameters. */
|
|
|
|
|
|
|
|
|
|
int r, drive, drive_id, nr_drives;
|
|
|
|
|
struct wini *wn;
|
|
|
|
|
unsigned long capacity;
|
|
|
|
|
struct int13ext_params {
|
|
|
|
|
u16_t len;
|
|
|
|
|
u16_t flags;
|
|
|
|
|
u32_t cylinders;
|
|
|
|
|
u32_t heads;
|
|
|
|
|
u32_t sectors;
|
|
|
|
|
u32_t capacity[2];
|
|
|
|
|
u16_t bts_per_sec;
|
|
|
|
|
u16_t config[2];
|
|
|
|
|
} *i13e_par;
|
|
|
|
|
struct reg86u reg86;
|
|
|
|
|
|
|
|
|
|
/* Ask the system task for a suitable buffer */
|
|
|
|
|
if(!(bios_buf_v = alloc_contig(BIOSBUF, AC_LOWER1M, &bios_buf_phys))) {
|
|
|
|
|
panic("allocating bios buffer failed: %d", ENOMEM);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bios_buf_phys+BIOSBUF > 0x100000)
|
|
|
|
|
panic("bad BIOS buffer / phys: %d", bios_buf_phys);
|
|
|
|
|
#if 0
|
|
|
|
|
printf("bios_wini: got buffer size %d, virtual 0x%x, phys 0x%x\n",
|
|
|
|
|
BIOSBUF, bios_buf_v, bios_buf_phys);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
i13e_par = (struct int13ext_params *) bios_buf_v;
|
|
|
|
|
|
|
|
|
|
/* Get the geometry of the drives */
|
|
|
|
|
for (drive = 0; drive < MAX_DRIVES; drive++) {
|
|
|
|
|
if (remap_first)
|
|
|
|
|
{
|
|
|
|
|
if (drive == 7)
|
|
|
|
|
drive_id= 0x80;
|
|
|
|
|
else
|
|
|
|
|
drive_id= 0x80 + drive + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
drive_id= 0x80 + drive;
|
|
|
|
|
|
|
|
|
|
(void) w_prepare(drive * DEV_PER_DRIVE);
|
|
|
|
|
wn = w_wn;
|
|
|
|
|
wn->drive_id= drive_id;
|
|
|
|
|
|
|
|
|
|
reg86.u.b.intno = 0x13;
|
|
|
|
|
reg86.u.b.ah = 0x08; /* Get drive parameters. */
|
|
|
|
|
reg86.u.b.dl = drive_id;
|
|
|
|
|
r= sys_int86(®86);
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("BIOS call failed: %d", r);
|
|
|
|
|
|
|
|
|
|
nr_drives = !(reg86.u.w.f & 0x0001) ? reg86.u.b.dl : drive;
|
|
|
|
|
if (drive_id >= 0x80 + nr_drives) continue;
|
|
|
|
|
wn->present= 1;
|
|
|
|
|
|
|
|
|
|
wn->heads = reg86.u.b.dh + 1;
|
|
|
|
|
wn->sectors = reg86.u.b.cl & 0x3F;
|
|
|
|
|
wn->cylinders = (reg86.u.b.ch | ((reg86.u.b.cl & 0xC0) << 2)) + 1;
|
|
|
|
|
|
|
|
|
|
capacity = (unsigned long) wn->cylinders * wn->heads * wn->sectors;
|
|
|
|
|
|
|
|
|
|
reg86.u.b.intno = 0x13;
|
|
|
|
|
reg86.u.b.ah = 0x41; /* INT 13 Extensions - Installation check */
|
|
|
|
|
reg86.u.w.bx = 0x55AA;
|
|
|
|
|
reg86.u.b.dl = drive_id;
|
|
|
|
|
|
|
|
|
|
r= sys_int86(®86);
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("BIOS call failed: %d", r);
|
|
|
|
|
|
|
|
|
|
if (!(reg86.u.w.f & 0x0001) && reg86.u.w.bx == 0xAA55
|
|
|
|
|
&& (reg86.u.w.cx & 0x0001)) {
|
|
|
|
|
/* INT 13 Extensions available. */
|
|
|
|
|
i13e_par->len = 0x001E; /* Input size of parameter packet */
|
|
|
|
|
reg86.u.b.intno = 0x13;
|
|
|
|
|
reg86.u.b.ah = 0x48; /* Ext. Get drive parameters. */
|
|
|
|
|
reg86.u.b.dl = drive_id;
|
|
|
|
|
reg86.u.w.si = bios_buf_phys % HCLICK_SIZE;
|
|
|
|
|
reg86.u.w.ds = bios_buf_phys / HCLICK_SIZE;
|
|
|
|
|
|
|
|
|
|
r= sys_int86(®86);
|
|
|
|
|
if (r != OK)
|
|
|
|
|
panic("BIOS call failed: %d", r);
|
|
|
|
|
|
|
|
|
|
if (!(reg86.u.w.f & 0x0001)) {
|
|
|
|
|
wn->int13ext = 1; /* Extensions can be used. */
|
|
|
|
|
capacity = i13e_par->capacity[0];
|
|
|
|
|
if (i13e_par->capacity[1] != 0) capacity = 0xFFFFFFFF;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wn->int13ext) {
|
|
|
|
|
printf("bios-d%u: %lu sectors\n", w_drive, capacity);
|
|
|
|
|
} else {
|
|
|
|
|
printf("bios-d%u: %d cylinders, %d heads, "
|
|
|
|
|
"%d sectors per track\n",
|
|
|
|
|
w_drive, wn->cylinders, wn->heads, wn->sectors);
|
|
|
|
|
}
|
|
|
|
|
wn->part[0].dv_size = mul64u(capacity, SECTOR_SIZE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*============================================================================*
|
|
|
|
|
* w_geometry *
|
|
|
|
|
*============================================================================*/
|
|
|
|
|
static void w_geometry(dev_t minor, struct partition *entry)
|
|
|
|
|
{
|
|
|
|
|
if (w_prepare(minor) == NULL) return;
|
|
|
|
|
|
|
|
|
|
entry->cylinders = w_wn->cylinders;
|
|
|
|
|
entry->heads = w_wn->heads;
|
|
|
|
|
entry->sectors = w_wn->sectors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*============================================================================*
|
|
|
|
|
* w_ioctl *
|
|
|
|
|
*============================================================================*/
|
|
|
|
|
static int w_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
|
|
|
|
|
cp_grant_id_t grant)
|
|
|
|
|
{
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
if (w_prepare(minor) == NULL) return ENXIO;
|
|
|
|
|
|
|
|
|
|
if (request == DIOCOPENCT) {
|
|
|
|
|
count = w_wn->open_ct;
|
|
|
|
|
return sys_safecopyto(endpt, grant, 0, (vir_bytes)&count,
|
|
|
|
|
sizeof(count), D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|