📄 ide.c
字号:
/*** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.** Modified Sep 2001 by 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 <newos/errors.h>#include <kernel/arch/cpu.h>#include <kernel/arch/int.h>#include <string.h>#include <stdio.h>#include <kernel/dev/arch/i386/ide/ide_bus.h>#include <kernel/fs/devfs.h>#include "ide_private.h"#include "ide_raw.h"ide_device devices[MAX_DEVICES];sem_id ide_sem;#define IDE_0_INTERRUPT 14#define IDE_1_INTERRUPT 15#define MAX_PARTITIONS 8typedef struct{ ide_device* dev; // Pointer to entry in 'devices' table // Specs for whole disk or partition uint32 block_start; // Number of first block uint32 block_count; // Number of blocks used uint16 block_size; // Bytes per block} ide_ident;//--------------------------------------------------------------------------------static int ide_open(dev_ident _ident, dev_cookie *cookie){ ide_ident* ident = (ide_ident*)_ident; // We hold our 'ident' structure as cookie, as it contains all we need *cookie = ident; return NO_ERROR;}//--------------------------------------------------------------------------------static int ide_close(dev_cookie _cookie){ return NO_ERROR;}//--------------------------------------------------------------------------------static int ide_freecookie(dev_cookie cookie){ // We do not have anything to free here, as our cookie is our // dev_ident as well :) return NO_ERROR;}//--------------------------------------------------------------------------------static int ide_seek(dev_cookie cookie, off_t pos, seek_type st){ return ERR_UNIMPLEMENTED;}//--------------------------------------------------------------------------------static int ide_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.heads; drive_geometry->cylinders = device->hardware_device.cyls; drive_geometry->sectors = device->hardware_device.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 int ide_ioctl(dev_cookie _cookie, int op, void *buf, size_t len){ ide_ident* cookie = (ide_ident*)_cookie; int err = 0; sem_acquire(ide_sem, 1); switch(op) { case DISK_GET_GEOMETRY: err = ide_get_geometry(cookie->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; case DISK_GET_ACCOUSTIC_LEVEL: if (len != sizeof(int8)) { err = ERR_INVALID_ARGS; } else { err = ide_get_accoustic(cookie->dev, (int8*)buf); } break; case DISK_SET_ACCOUSTIC_LEVEL: if (len != sizeof(int8)) { err = ERR_INVALID_ARGS; } else { err = ide_set_accoustic(cookie->dev,*(int8*)buf); } break; default: err = ERR_INVALID_ARGS; } sem_release(ide_sem, 1); return err;}//--------------------------------------------------------------------------------static ssize_t ide_read(dev_cookie _cookie, void *buf, off_t pos, ssize_t len){ ide_ident* cookie = (ide_ident*)_cookie; uint32 sectors; uint32 currentSector; uint32 sectorsToRead; uint32 block; if (cookie == NULL) { return ERR_INVALID_ARGS; } // Make sure noone else is doing IDE sem_acquire(ide_sem, 1); // Calculate start block and number of blocks to read block = pos / cookie->block_size; block += cookie->block_start; sectors = len / cookie->block_size; // correct len to be the actual # of bytes to read len -= len % cookie->block_size; // If it goes beyond the disk/partition, exit if (block + sectors > cookie->block_start + cookie->block_count) { sem_release(ide_sem, 1); return 0; } // Start reading the sectors currentSector = 0; while(currentSector < sectors) { // Read max. of 255 sectors at a time sectorsToRead = (sectors - currentSector) > 255 ? 255 : sectors; // If the read fails, exit with I/O error if (ide_read_block(cookie->dev, buf, block, sectorsToRead) != 0) { sem_release(ide_sem, 1); return ERR_IO_ERROR; } // Move to next block to read block += sectorsToRead * cookie->block_size; currentSector += sectorsToRead; } // Give up sem_release(ide_sem, 1); return len;}//--------------------------------------------------------------------------------static ssize_t ide_write(dev_cookie _cookie, const void *buf, off_t pos, ssize_t len){ int block; ide_ident* cookie = _cookie; uint32 sectors; uint32 currentSector; uint32 sectorsToWrite; dprintf("ide_write: entry buf %p, pos 0x%Lx, *len %Ld\n", buf, pos, (long long)len); if(cookie == NULL) { return ERR_INVALID_ARGS; } // Make sure no other I/O is done sem_acquire(ide_sem, 1); // Get the start pos and block count to write block = pos / cookie->block_size + cookie->block_start; sectors = len / cookie->block_size; // If we're writing more than the disk/partition size if (block + sectors > cookie->block_start + cookie->block_count) { // exit without writing sem_release(ide_sem, 1); return 0; } // Loop over sectors to write currentSector = 0; while(currentSector < sectors) { // Write a max of 255 sectors at a time sectorsToWrite = (sectors - currentSector) > 255 ? 255 : sectors; // Write them if (ide_write_block(cookie->dev, buf, block, sectorsToWrite) != 0) { // dprintf("ide_write: ide_block returned %d\n", rc); len = currentSector * cookie->block_size; sem_release(ide_sem, 1); return ERR_IO_ERROR; } block += sectorsToWrite * cookie->block_size; currentSector += sectorsToWrite; } sem_release(ide_sem, 1); return len;}//--------------------------------------------------------------------------------static int ide_canpage(dev_ident ident){ return false;}//--------------------------------------------------------------------------------static ssize_t ide_readpage(dev_ident ident, iovecs *vecs, off_t pos){ return ERR_UNIMPLEMENTED;}//--------------------------------------------------------------------------------static ssize_t ide_writepage(dev_ident ident, iovecs *vecs, off_t pos){ return ERR_UNIMPLEMENTED;}//--------------------------------------------------------------------------------static struct dev_calls ide_hooks = { ide_open, ide_close, ide_freecookie, ide_seek, ide_ioctl, ide_read, ide_write, ide_canpage, ide_readpage, ide_writepage};//--------------------------------------------------------------------------------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, int16 partition){ ide_ident* ident = kmalloc(sizeof(ide_ident)); if (ident != NULL) { ident->dev = dev; ident->block_size = dev->bytes_per_sector; if (partition >= 0 && partition < MAX_PARTITIONS) { ident->block_start = dev->partitions[partition].starting_block; ident->block_count = dev->partitions[partition].sector_count; } else { ident->block_start = 0; ident->block_count = dev->sector_count; } } return ident;}//--------------------------------------------------------------------------------static bool ide_attach_device(int bus, int device){ ide_device* ide = &devices[(bus*2) + device]; ide_ident* ident = NULL; char devpath[256]; int part; ide->bus = bus; ide->device = device; if (ide_identify_device(bus, device)) { ide->magic = IDE_MAGIC_COOKIE; ide->magic2 = IDE_MAGIC_COOKIE2; if (ide_get_partitions(ide)) { for (part=0; part < NUM_PARTITIONS*2; part++) { if (ide->partitions[part].partition_type != 0 && (ident=ide_create_device_ident(ide, part)) != NULL) { sprintf(devpath, "disk/ide/ata/%d/%d/%d", bus, device, part); devfs_publish_device(devpath, ident, &ide_hooks); } } dprintf("ide_attach_device(bus=%d,dev=%d) rc=true\n", bus, device); return true; } } dprintf("ide_attach_device(bus=%d,dev=%d) rc=false\n", bus, device); return false;}//--------------------------------------------------------------------------------static bool ide_attach_buses(unsigned int bus){ char devpath[256]; int found = 0; int dev; for(dev=0; dev < 2; dev++) if (ide_attach_device(bus, dev)) found++; return(found > 0 ? true : false);}//--------------------------------------------------------------------------------// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING//--------------------------------------------------------------------------------// Don't try and attach more then one bus to the driver, as ide_raw_init// overwrites globals and you end up writing blocks which were meant// for bus #1 to bus #2 :(//// !!!!!! So, only use the one or the other, _never_ both !!!!!!//--------------------------------------------------------------------------------int ide_bus_init(kernel_args *ka){ // Create our top-level semaphore ide_sem = sem_create(1, "ide_sem"); if (ide_sem < 0) { // We failed, so tell caller return ide_sem; } // attach ide bus #1 int_set_io_interrupt_handler(IDE_0_INTERRUPT, &ide_interrupt_handler, NULL); ide_raw_init(0x1f0, 0x3f0); ide_attach_buses(0); // attach ide bus #2// int_set_io_interrupt_handler(IDE_1_INTERRUPT, &ide_interrupt_handler, NULL);// ide_raw_init(0x170, 0x370);// ide_attach_buses(1); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -