⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bios_wini.c

📁 minix操作系统最新版本(3.1.1)的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -