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

📄 ide.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.** Copyright 2001-2002, Rob Judd <judd@ob-wan.com>** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/console.h>#include <kernel/debug.h>#include <kernel/heap.h>#include <kernel/int.h>#include <kernel/sem.h>#include <kernel/vfs.h>#include <kernel/vm.h>#include <newos/errors.h>#include <kernel/arch/cpu.h>#include <kernel/arch/int.h>//#include <kernel/dev/arch/i386/ide/ide_bus.h>#include <kernel/fs/devfs.h>#include <string.h>#include <stdio.h>#include "ide_private.h"#include "ide_raw.h"ide_device      devices[MAX_IDE_DEVICES];sem_id ide_sem, ide_sem_0, ide_sem_1;#define IDE_0_INTERRUPT  14#define IDE_1_INTERRUPT  15struct ide_ident {	ide_device* dev;	// specs for whole disk or partition	off_t       block_start;	off_t       block_count;	uint16      block_size;	off_t       length;      // count * size	// temporary work buffer	char        work_buf[0]; // size of a block};typedef struct ide_ident ide_ident;struct ide_cookie {	ide_ident *ident;	off_t pos;};typedef struct ide_cookie ide_cookie;//--------------------------------------------------------------------------------static int ide_open(dev_ident _ident, dev_cookie *_cookie){	ide_ident* ident = (ide_ident*)_ident;	ide_cookie *cookie;	cookie = (ide_cookie *)kmalloc(sizeof(ide_cookie));	if(!cookie)		return ERR_NO_MEMORY;	cookie->ident = ident;	cookie->pos = 0;	dprintf("ide_open: ident %p, start 0x%Lx, count 0x%Lx, size 0x%x\n", 		ident, ident->block_start, ident->block_count, ident->block_size);	*_cookie = cookie;	return NO_ERROR;}//--------------------------------------------------------------------------------static int ide_close(dev_cookie _cookie){	return NO_ERROR;}//--------------------------------------------------------------------------------static int ide_freecookie(dev_cookie _cookie){	ide_cookie *cookie = (ide_cookie *)_cookie;	kfree(cookie);	return NO_ERROR;}//--------------------------------------------------------------------------------static int ata_execute_diagnostic(ide_device* dev){	uint8 err;	uint8* buf = (uint8*)&dev->_reserved;	err = ata_cmd(dev->bus, 0, CMD_EXECUTE_DRIVE_DIAGNOSTIC, buf);	if(err == NO_ERROR)		return (int)buf;	return NO_ERROR;}//--------------------------------------------------------------------------------static int ata_get_geometry(ide_device* device, void *buf, size_t len){	drive_geometry* drive_geometry = buf;	if (len < sizeof(drive_geometry))		return ERR_VFS_INSUFFICIENT_BUF;	drive_geometry->blocks = device->end_block - device->start_block;	drive_geometry->heads = device->hardware_device.curr_heads;	drive_geometry->cylinders = device->hardware_device.curr_cyls;	drive_geometry->sectors = device->hardware_device.curr_sectors;	drive_geometry->removable = false;	drive_geometry->bytes_per_sector = device->bytes_per_sector;	drive_geometry->read_only = false;	strcpy(drive_geometry->model, device->hardware_device.model);	strcpy(drive_geometry->serial, device->hardware_device.serial);	strcpy(drive_geometry->firmware, device->hardware_device.firmware);	return NO_ERROR;}//--------------------------------------------------------------------------------static void bus_acquire(ide_ident* ident){	if (ident->dev->bus == 0)		sem_acquire(ide_sem_0, 1);	if (ident->dev->bus == 1)		sem_acquire(ide_sem_1, 1);};//--------------------------------------------------------------------------------static void bus_release(ide_ident* ident){	if(ident->dev->bus == 0)		sem_release(ide_sem_0, 1);	if(ident->dev->bus == 1)		sem_release(ide_sem_1, 1);};//--------------------------------------------------------------------------------static int ide_ioctl(dev_cookie _cookie, int op, void *buf, size_t len){	ide_cookie* cookie = (ide_cookie*)_cookie;	int err = 0;	if(cookie == NULL)		return ERR_INVALID_ARGS;	bus_acquire(cookie->ident);	switch(op) {		case DISK_EXECUTE_DIAGNOSTIC:			err = ata_execute_diagnostic(cookie->ident->dev);			break;		case DISK_GET_GEOMETRY:			err = ata_get_geometry(cookie->ident->dev, buf, len);			break;		case DISK_USE_DMA:		case DISK_USE_BUS_MASTERING:			err = ERR_UNIMPLEMENTED;			break;		case DISK_USE_PIO:			err = NO_ERROR;			break;		default:			err = ERR_INVALID_ARGS;	}	bus_release(cookie->ident);	return err;}//--------------------------------------------------------------------------------static ssize_t ide_read(dev_cookie _cookie, void *buf, off_t pos, ssize_t len){	ide_cookie *cookie = (ide_cookie*)_cookie;	ide_ident  *ident = cookie->ident;	uint32		curr_sector;	int         err;	int         offset, copy_len;	ssize_t     bytes_read = 0;	dprintf("ide_read: cookie %p, entry buf %p, pos 0x%Lx, len %ld, cookie->pos 0x%Lx\n", 		cookie, buf, pos, len, cookie->pos);	dprintf("\tblock_start 0x%Lx, block_count 0x%Lx, block_size 0x%x\n",		ident->block_start, ident->block_count, ident->block_size);	if (cookie == NULL)		return ERR_INVALID_ARGS;	bus_acquire(ident);	// if pos is negative, use the current cookie position	if(pos < 0)		pos = cookie->pos;	// make sure we're within the device	if(pos >= ident->length) {		bytes_read = 0;		goto out;	}	// trim the read length if necessary	if(pos + len > ident->length)		len = ident->length - pos;		// calculate the starting sector	curr_sector = pos / ident->block_size;	curr_sector += ident->block_start;	// read the blocks into a temporary buffer, then copy into user space	// XXX remove the intermediate read	if(len > 0) {		err = ata_read_sector(ident->dev, ident->work_buf, curr_sector, 1);		if(err < 0) {			bytes_read = err;			goto out;		}		offset = pos % ident->block_size;		copy_len = ident->block_size - offset;		err = user_memcpy(buf, ident->work_buf + offset, copy_len); 		if(err < 0) {			bytes_read = err;			goto out;		}		pos += copy_len;		bytes_read += copy_len;		len -= copy_len;		curr_sector++;	}	cookie->pos = pos;out:	bus_release(cookie->ident);	dprintf("ide_read: returning %ld\n", bytes_read);	return bytes_read;}//--------------------------------------------------------------------------------static ssize_t ide_write(dev_cookie _cookie, const void *buf, off_t pos, ssize_t len){	int			block;	ide_cookie*	cookie = (ide_cookie *)_cookie;	uint32		sectors;	uint32		currentSector;	uint32		sectorsToWrite;	dprintf("ide_write: cookie %p, entry buf %p, pos 0x%Lx, len %ld\n", cookie, buf, pos, len);	if(cookie == NULL)		return ERR_INVALID_ARGS;	bus_acquire(cookie->ident);	if(pos < 0)		pos = cookie->pos;	block = pos / cookie->ident->block_size + cookie->ident->block_start;	sectors = len / cookie->ident->block_size;	// exit if write exceeds partition size	if (block + sectors > cookie->ident->block_start + cookie->ident->block_count) {		bus_release(cookie->ident);		return ERR_INVALID_ARGS;	}	currentSector = 0;	while(currentSector < sectors) {		sectorsToWrite = (sectors - currentSector) > 255 ? 255 : sectors;		if (ata_write_sector(cookie->ident->dev, buf, block, sectorsToWrite) != NO_ERROR) {			//  dprintf("ide_write: ide_block returned %d\n", rc);			len = currentSector * cookie->ident->block_size;			bus_release(cookie->ident);			return ERR_IO_ERROR;		}		block += sectorsToWrite * cookie->ident->block_size;		currentSector += sectorsToWrite;		pos += sectorsToWrite * cookie->ident->block_size;	}	cookie->pos = pos;	bus_release(cookie->ident);	return len;}//--------------------------------------------------------------------------------static int ide_seek(dev_cookie _cookie, off_t pos, seek_type st){	ide_cookie *cookie = (ide_cookie *)_cookie;	int err = 0;	bus_acquire(cookie->ident);	switch(st) {		case _SEEK_END:			pos += (cookie->ident->block_start + cookie->ident->block_count) * cookie->ident->block_size;			goto _SEEK_SET;		case _SEEK_CUR:			pos += cookie->pos;_SEEK_SET:		case _SEEK_SET:			if(pos < 0)				pos = 0;			if(pos > (cookie->ident->block_start + cookie->ident->block_count) * cookie->ident->block_size)				pos = (cookie->ident->block_start + cookie->ident->block_count) * cookie->ident->block_size;			cookie->pos = pos;			break;		default:			err = ERR_INVALID_ARGS;	}	bus_release(cookie->ident);	return err;}//--------------------------------------------------------------------------------static struct dev_calls ide_hooks = {	ide_open,	ide_close,	ide_freecookie,	ide_seek,	ide_ioctl,	ide_read,	ide_write,	// can't page from ide devices	NULL,	NULL,	NULL};//--------------------------------------------------------------------------------static int ide_interrupt_handler(void* data){  dprintf("in ide interrupt handler\n");  return INT_RESCHEDULE;}//--------------------------------------------------------------------------------static ide_ident* ide_create_device_ident(ide_device* dev){	ide_ident* ident = kmalloc(sizeof(ide_ident) + dev->bytes_per_sector);	if (ident != NULL) {		ident->dev = dev;		ident->block_size = dev->bytes_per_sector;		ident->block_start = 0;		ident->block_count = dev->sector_count;		ident->length = ident->block_count * ident->block_size;	}	return ident;}//--------------------------------------------------------------------------------static bool ide_attach_devices(int bus, int device){	ide_device*  ide = &devices[(bus*2) + device];	ide_ident*   ident = NULL;	char         devpath[256];	uint8        part, type;	ide->bus    = bus;	ide->device = device;    type = ide_identify_device(bus, device);	// register all hdd partitions with devfs	if (type == ATA_DEVICE) {		ide->magic1 = IDE_MAGIC_COOKIE1;        ide->magic2 = IDE_MAGIC_COOKIE2;#if 0		if (ata_get_partitions(ide)) {			for (part=0; part < MAX_PARTITIONS; part++) {				if (ide->partitions[part].partition_type != 0 &&					(ident=ide_create_device_ident(ide, part)) != NULL) {					sprintf(devpath, "disk/ata/%d/%d/%d", bus, device, part);					devfs_publish_device(devpath, ident, &ide_hooks);				}			}	dprintf("ide_attach_devices(bus=%d,dev=%d) rc=ata_device\n", bus, device);			return true;		}#endif		// register a raw ide device		if((ident = ide_create_device_ident(ide)) != NULL) {			sprintf(devpath, "disk/ata/%d/%d/raw", bus, device);			devfs_publish_device(devpath, ident, &ide_hooks);			dprintf("ide_attach_devices(bus=%d,dev=%d) rc=ata_device\n", bus, device);			dprintf("\tdev %p, ident %p, start 0x%Lx, count 0x%Lx, blocksize 0x%x\n", 				ide, ident, ident->block_start, ident->block_count, ident->block_size);			return true;		}	}	// register cd/dvd drives with devfs	// plugins handle partitions due to multitude of formats	if (type == ATAPI_DEVICE) {		sprintf(devpath, "disk/atapi/%d/%d", bus, device);		devfs_publish_device(devpath, ident, &ide_hooks);	dprintf("ide_attach_devices(bus=%d,dev=%d) rc=atapi_device\n", bus, device);		return true;	}	dprintf("ide_attach_devices(bus=%d,dev=%d) rc=no_device\n", bus, device);	return false;}//--------------------------------------------------------------------------------static bool ide_attach_bus(int bus){	uint8 dev, found = 0;	for(dev=0; dev < 2; dev++)		if (ide_attach_devices(bus, dev))			found++;	return(found > 0 ? true : false);}//--------------------------------------------------------------------------------int dev_bootstrap(void);int dev_bootstrap(void){	// create top-level semaphore for ide bus #1	if ((ide_sem = sem_create(1, "ide_sem_0")) < 0)		return ide_sem;	// attach ide bus #1	int_set_io_interrupt_handler(IDE_0_INTERRUPT, &ide_interrupt_handler, NULL, "ide0");	ide_raw_init(0x1f0, 0x3f0);	ide_attach_bus(0);	// create top-level semaphore for ide bus #2	if ((ide_sem = sem_create(1, "ide_sem_1")) < 0)		return ide_sem;	// attach ide bus #2	int_set_io_interrupt_handler(IDE_1_INTERRUPT, &ide_interrupt_handler, NULL, "ide1");	ide_raw_init(0x170, 0x370);	ide_attach_bus(1);	return NO_ERROR;}

⌨️ 快捷键说明

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