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

📄 hd.c

📁 一个操作系统,用C语言实现开发的,我在一个浙江大学的操作系统实验网站找到.大家学习以下
💻 C
📖 第 1 页 / 共 2 页
字号:
// Kernel
// Default Driver IDE

#include <string.h>
#include <memory.h>
#include <gates.h>
#include <knlsched.h>
#include <knlcon.h>
#include <knllib.h>
#include <devices.h>
#include <vfs.h>
#include "hd.h"

#define IDE_TIMEOUT	5000

#define DR_CMDMASK	0x0000000f
#define DR_READ		0x00000001
#define DR_WRITE	0x00000002
#define MAX_CMDBYTES	16
#define DEF_SECTORSIZE	512
#define DEF_CACHELIMIT	64

typedef struct _DEVREQUEST
{
	HDEVICE device;
	_u32 buffer;
	_u32 blocks;
	_u32 flags;
	_u32 errcode;
	int bytes;					// cmd bytes
	int ports[MAX_CMDBYTES];	// cmd ports
	int values[MAX_CMDBYTES];	// cmd data
	void *data;					// external data
} DEVREQUEST;

extern void irq_hd(void);

static HDRIVER _this_driver;
static DRIVE _hdd_drives[4];	// 0x80-0x83
static REQUESTQUEUE _hdd_requestqueue;

static int wait_ide(int pri_sec)
{
	_u32 ticks;
	int r;

	ticks = GetSystemTicks();
	while(((r=_inb(pri_sec+HDPA_STATUS))&0x80) && GetSystemTicks()-ticks<IDE_TIMEOUT);
	return r;
}

static int ide_ready(int pri_sec)
{
	_u32 ticks;
	int r;

	ticks = GetSystemTicks();
	while((r=_inb(pri_sec+HDPA_STATUS)&0xc0)!=0x40 && GetSystemTicks()-ticks<IDE_TIMEOUT);
	return r;
}

static void reset_ide(int pri_sec)
{
	_outb(pri_sec+HDPA_CMD, 0x08);
	wait_ide(pri_sec);
}

static inline void reset_drive(int pri_sec, int drv)
{
	reset_ide(pri_sec);
	_outb(pri_sec+HDPA_HEAD, (0xa0|(drv<<4)));
	_outb(pri_sec+HDPA_CMD, 0x91);
	wait_ide(pri_sec);
}

static inline int lba_to_chs(int id, _u32 sector, _u32 *cyl, _u32 *head, _u32 *sec)
{
	if(!DRIVE_VALID(_hdd_drives[id])) return -1;
	if(sec) *sec = (sector+1)%_hdd_drives[id].n_sectors;
	if(head) *head = ((sector+1)/_hdd_drives[id].n_sectors)%_hdd_drives[id].n_heads;
	if(cyl) *cyl = ((sector+1)/_hdd_drives[id].n_sectors)/_hdd_drives[id].n_heads;
	return 0;
}

static inline _u32 chs_to_lba(int id, _u32 cyl, _u32 head, _u32 sec)
{
	if(!DRIVE_VALID(_hdd_drives[id])) return -1;
	return (cyl*_hdd_drives[id].n_heads+head)*_hdd_drives[id].n_sectors+sec-1;
}

static int hdd_read(int id, _u32 addr, void* buf, int nr)
{
	_u32 c, h, s;
	int chs, port, r;

	if(!DRIVE_VALID(_hdd_drives[id])) return HDE_INVALID;
	if(!(_hdd_drives[id].capbilities&HDC_LBA))
	{
		if(lba_to_chs(id, addr, &c, &h, &s)!=0) return HDE_ADDRESS;
		if(c>=_hdd_drives[id].n_cylinders || h>=_hdd_drives[id].n_heads
		   || s>_hdd_drives[id].n_sectors) return HDE_ADDRESS;
		chs = 1;
	}
	else
	{
		if(addr>=_hdd_drives[id].n_LBAsectors) return HDE_ADDRESS;
		chs = 0;
	}

	port = _hdd_drives[id].port_base;

	reset_drive(port, _hdd_drives[id].drive_id);
	r = ide_ready(port);
	if(r!=0x40) return HDE_READY|r;

	_outb(++port, 0);
	_outb(++port, nr);
	if(chs)
	{
		_outb(++port, s);
		_outb(++port, c);
		_outb(++port, (c>>8));
		_outb(++port, (0xa0|(_hdd_drives[id].drive_id<<4)|h));
		_outb(++port, 0x20);
	}
	else
	{
		_outb(++port, addr);
		_outb(++port, (addr>>8));
		_outb(++port, (addr>>16));
		_outb(++port, (0xe0|(_hdd_drives[id].drive_id<<4)|((addr>>24)&0x0f)));
		_outb(++port, 0x20);
	}

	port = _hdd_drives[id].port_base;
	// Wait until job is done
	if((wait_ide(port)&0x58)!=0x58)
	{
		int r = _inb(port+HDPA_ERR)&0x00ff;
		reset_drive(port, _hdd_drives[id].drive_id);
		return IDE_TIMEOUT|r;
	}

	// Read data
	_insw(port, buf, nr*256);
	return 0;
}

static int build_cmds(DEVREQUEST *req, _u32 sector, int cmd)
{
	_u32 c, h, s;
	int chs, port;

	HDDEVICE *hddev = (HDDEVICE*)GetDeviceExtraMem(req->device);


	if(sector>=hddev->length) return HDE_ADDRESS;
	if(req->blocks>hddev->length-sector) req->blocks = hddev->length-sector;
	sector+=hddev->base;
	if(!(_hdd_drives[hddev->drive].capbilities&HDC_LBA))
	{
		if(lba_to_chs(hddev->drive, sector, &c, &h, &s)!=0) return HDE_ADDRESS;
		if(c>=_hdd_drives[hddev->drive].n_cylinders
		   || h>=_hdd_drives[hddev->drive].n_heads
		   || s>_hdd_drives[hddev->drive].n_sectors) return HDE_ADDRESS;
		chs = 1;
	}
	else
	{
		if(sector>=_hdd_drives[hddev->drive].n_LBAsectors) return HDE_ADDRESS;
		chs = 0;
	}

	port = _hdd_drives[hddev->drive].port_base;
	req->ports[0] = ++port; req->values[0] = 0;
	req->ports[1] = ++port; req->values[1] = req->blocks;
	if(chs)
	{
		req->ports[2] = ++port; req->values[2] = s;
		req->ports[3] = ++port; req->values[3] = c;
		req->ports[4] = ++port; req->values[4] = c>>8;
		req->ports[5] = ++port; req->values[5] = 0xa0|(_hdd_drives[hddev->drive].drive_id<<4)|h;
	}
	else
	{
		req->ports[2] = ++port; req->values[2] = sector;
		req->ports[3] = ++port; req->values[3] = sector>>8;
		req->ports[4] = ++port; req->values[4] = sector>>16;
		req->ports[5] = ++port; req->values[5] = 0xe0|(_hdd_drives[hddev->drive].drive_id<<4)|((sector>>24)&0x0f);
	}
	req->ports[6] = ++port; req->values[6] = cmd;
	req->bytes = 7;

	return 0;
}

struct buf_request
{
	BUFFERITEM *pItem;
	HDEVICE hDev;
	int op;
	int result;
};

static long __syscall hd_queue_proc(REQUESTQUEUE *pQueue, _u32 cmd, _u32 param1, _u32 param2)
{
	switch(cmd)
	{
	case RQ_CREATEREQUEST:
		{
			REQUEST *r = (REQUEST*)param1;
			struct buf_request *pbr = (struct buf_request*)param2;
			DEVREQUEST *req = rqGetRequestExtraMem(r);

			KASSERT(req, "HD RQ_CREATEREQUEST: null RequestExtraMem");

			req->device  = pbr->hDev;
			req->buffer  = (_u32)pbr->pItem->buffer;
			req->blocks  = GetDeviceBufferList(pbr->hDev)->item_size/DEF_SECTORSIZE;
			req->flags   = pbr->op;
			req->errcode = HDE_NOTDONE;
			req->data	 = pbr;

			pbr->result = build_cmds(req, pbr->pItem->base, pbr->op==DR_READ?0x20:0x30);
			return pbr->result==0 ? ERR_SUCCESS : ERR_DEVICE;
		}
		break;
	case RQ_PENDREQUEST:
		{
			REQUEST *r = (REQUEST*)param1;
			DEVREQUEST *req = (DEVREQUEST*)param2;
			HDDEVICE *hddev;
			int n;

			KASSERT(req, "HD RQ_PENDREQUEST: null RequestExtraMem");
			hddev = GetDeviceExtraMem(req->device);
			KASSERT(hddev, "HD RQ_PENDREQUEST: null DeviceExtraMem");

			SysLock();
			// Reset drive
			EnableIRQ(0x0e, 0);
			reset_drive(_hdd_drives[hddev->drive].port_base,
						_hdd_drives[hddev->drive].drive_id);
			n = ide_ready(_hdd_drives[hddev->drive].port_base);
			if(n!=0x40)
			{
				req->errcode = HDE_READY|n;
				r->status = RS_COMPLETE;
				EnableIRQ(0x0e, 1);			
				SysUnlock();	
				return req->errcode;
			}
			// Write commands, HD interrupt should be masked
			for(n=0; n<req->bytes; n++)
				_outb(req->ports[n], req->values[n]);
			EnableIRQ(0x0e, 1);

			SysUnlock();
		}
		break;
	case RQ_SUBMIT:
		{
			DEVREQUEST *req = rqGetRequestExtraMem((REQUEST*)param1);
			KASSERT(req, "HD RQ_SUBMIT: null req");
			KASSERT(req->data, "HD RQ_SUBMIT: null req->data");
			((struct buf_request*)req->data)->result = req->errcode;
		}
		break;
	}
	return 0;
}

static long __syscall hd_buffers_proc(BUFFERLIST *pList, _u32 cmd, _u32 param1, _u32 param2)
{
	switch(cmd)
	{
	case BL_CREATE:
		{
			HDEVICE hDev	= (HDEVICE)param2;
			HDDEVICE *pDev	= GetDeviceExtraMem(hDev);

			KASSERT2(pDev, "HD BL_CREATE: null DeviceExtraMem (handle: %08x, name: %s", hDev, hDev->caption);

			*(HDEVICE*)param1 = hDev;

			pList->flags		= BLF_FIXED | BLF_CACHELIMIT;
			pList->item_size 	= /*(_hdd_drives[pDev->drive].n_sectors+1) */ DEF_SECTORSIZE;
			pList->cache_size	= DEF_CACHELIMIT;
		}
		break;
	case BL_DESTROY: break;
	case BL_LOAD:
	case BL_FLUSH:
		{
			struct buf_request r;
			REQUEST *p;

			r.hDev  = *(HDEVICE*)bufsGetExtraMem(pList);
			r.pItem = (BUFFERITEM*)param1;
			r.op	= cmd==BL_LOAD ? DR_READ : DR_WRITE;
			p = rqNewRequest(&_hdd_requestqueue, (_u32)&r);
			if(!p) return DEVICE_MAKEERR(DEVERR_PARAMS);
			SysLock();
			rqAdd(p);					
			RescheduleReleaseLock();

			// after taskWakeup ...
			rqFree(p);
			return r.result;
		}
		break;
	}
	return 0;
}

static long doTransfer(HDEVICE dev, DDTPACKET *pack, _u32 *len, int dr_cmd)
{
	BUFFERLIST *pList;
	BUFFERITEM *pItem;
	HDDEVICE *pDev;
	_u32 pointer, base, offset, byteoff;
	char *buffer;
	long l0, l1, ret;
	int l;

	pList = GetDeviceBufferList(dev);
	pDev = GetDeviceExtraMem(dev);
	KASSERT(pList, "doTransfer: null pList");
	KASSERT(pDev, "doTransfer: null pDev");
	KASSERT1(pDev->drive>=0 && pDev->drive<4, "doTransfer: invalid drive %d", pDev->drive);

	pointer = pack->pointer; l0 = pack->blocks * DEF_SECTORSIZE; l1 = 0;
	buffer = (char*)pack->buffer;
	if(len) *len = 0;
	while(l0>0)
	{
		KASSERT(pList->item_size, "doTransfer: pList->item_size = 0");
		offset = pointer%(pList->item_size/DEF_SECTORSIZE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -