?? bios_wini.c
字號:
/* 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 "../drivers.h"#include "../libdriver/driver.h"#include "../libdriver/drvlib.h"#include <minix/sysutil.h>#include <minix/keymap.h>#include <sys/ioc_disk.h>#include <ibm/int86.h>#include <assert.h>#define ME "BIOS_WINI"/* Error codes */#define ERR (-1) /* general error *//* Parameters for the disk drive. */#define MAX_DRIVES 8 /* this driver supports 8 drives (d0 - d7)*/#define MAX_SECS 255 /* bios can transfer this many sectors */#define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE)#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)PRIVATE int pc_at = 1; /* What about PC XTs? *//* Variables. */PRIVATE 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;PRIVATE int w_drive; /* selected drive */PRIVATE struct device *w_dv; /* device's base and size */PRIVATE vir_bytes bios_buf_vir, bios_buf_size;PRIVATE phys_bytes bios_buf_phys;PRIVATE int remap_first = 0; /* Remap drives for CD HD emulation */_PROTOTYPE(int main, (void) );FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );FORWARD _PROTOTYPE( char *w_name, (void) );FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position, iovec_t *iov, unsigned nr_req) );FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );FORWARD _PROTOTYPE( void w_init, (void) );FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry));FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr) );/* Entry points to this driver. */PRIVATE struct driver w_dtab = { w_name, /* current device's name */ w_do_open, /* open or mount request, initialize device */ w_do_close, /* release device */ do_diocntl, /* get or set a partition's geometry */ w_prepare, /* prepare for I/O on a given minor device */ w_transfer, /* do the I/O */ nop_cleanup, /* no cleanup needed */ w_geometry, /* tell the geometry of the disk */ nop_signal, /* no cleanup needed on shutdown */ nop_alarm, /* ignore leftover alarms */ nop_cancel, /* ignore CANCELs */ nop_select, /* ignore selects */ w_other, /* catch-all for unrecognized commands and ioctls */ NULL /* leftover hardware interrupts */};/*===========================================================================* * bios_winchester_task * *===========================================================================*/PUBLIC int main(){ long v; struct sigaction sa; sa.sa_handler = SIG_MESS; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGTERM,&sa,NULL)<0) panic("bios_wini","sigaction failed", errno); signal(SIGTERM, SIG_IGN); v= 0; env_parse("bios_remap_first", "d", 0, &v, 0, 1); remap_first= v;/* Set special disk parameters then call the generic main loop. */ driver_task(&w_dtab); return(OK);}/*===========================================================================* * w_prepare * *===========================================================================*/PRIVATE struct device *w_prepare(device)int 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(NIL_DEV); } if (w_drive >= MAX_DRIVES || !w_wn->present) return NIL_DEV; return(w_dv);}/*===========================================================================* * w_name * *===========================================================================*/PRIVATE char *w_name(){/* Return a name for the current device. */ static char name[] = "bios-d0"; name[6] = '0' + w_drive; return name;}/*===========================================================================* * w_transfer * *===========================================================================*/PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)int proc_nr; /* process doing the request */int opcode; /* DEV_GATHER or DEV_SCATTER */off_t position; /* offset on device to read or write */iovec_t *iov; /* pointer to read or write request vector */unsigned nr_req; /* length of request vector */{ struct wini *wn = w_wn; iovec_t *iop, *iov_end = iov + nr_req; int r, errors; unsigned nbytes, count, chunk; unsigned long block; vir_bytes i13e_rw_off, rem_buf_size; unsigned long dv_size = cv64ul(w_dv->dv_size); unsigned secspcyl = wn->heads * wn->sectors; 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; /* Check disk address. */ if ((position & SECTOR_MASK) != 0) return(EINVAL); errors = 0; i13e_rw_off= bios_buf_size-sizeof(i13e_rw); rem_buf_size= (i13e_rw_off & ~SECTOR_MASK); 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 (position >= dv_size) return(OK); /* At EOF */ if (position + nbytes > dv_size) nbytes = dv_size - position; block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE); /* Degrade to per-sector mode if there were errors. */ if (errors > 0) nbytes = SECTOR_SIZE; if (opcode == DEV_SCATTER) { /* Copy from user space to the DMA buffer. */ count = 0; for (iop = iov; count < nbytes; iop++) { chunk = iov->iov_size; if (count + chunk > nbytes) chunk = nbytes - count; assert(chunk <= rem_buf_size); r= sys_vircopy(proc_nr, D, iop->iov_addr, SYSTEM, D, bios_buf_vir+count, chunk); if (r != OK) panic(ME, "sys_vircopy failed", r); 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; r= sys_vircopy(SELF, D, (vir_bytes)&i13e_rw, SYSTEM, D, (bios_buf_vir+i13e_rw_off), sizeof(i13e_rw)); if (r != OK) panic(ME, "sys_vircopy failed", r); /* Set up an extended read or write BIOS call. */ reg86.u.b.intno = 0x13; reg86.u.w.ax = opcode == DEV_SCATTER ? 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 = opcode == DEV_SCATTER ? 0x03 : 0x02; reg86.u.b.al = nbytes >> SECTOR_SHIFT;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -