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

📄 ide_raw.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** Copyright 2001, Travis Geiselbrecht. All rights reserved.** Copyright 2001-2002, Rob Judd <judd@ob-wan.com>** Distributed under the terms of the NewOS License.**** With acknowledgements to Hale Landis <hlandis@ibm.net>** who wrote the reference implementation.*/#include <kernel/arch/cpu.h>#include <kernel/sem.h>#include <kernel/debug.h>#include <string.h>#include "ide_private.h"#include "ide_raw.h"// Waste some time by reading the alternate status a few times.// This gives the drive time to set BUSY in the status register on// really fast systems. If we don't do this, a slow drive on a fast// system may not set BUSY fast enough and we would think it had// completed the command when it really had not even started yet.#define DELAY400NS  { pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); \                      pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); }// Standard ide base addresses. For pc-card (pcmcia) drives, use// unused contiguous address block { 100H < (base1=base2) < 3F0H }// Non-standard addresses also exist. For ATA via sound cards try:// pio_base2 = 168/368, irq 9 or 10// pio_base3 = 1e8/3e8, irq 11 or 12unsigned int pio_base0_addr1 = 0x1f0; // Command block, ide bus 0unsigned int pio_base0_addr2 = 0x3f0; // Control block, ide bus 0unsigned int pio_base1_addr1 = 0x170; // Command block, ide bus 1unsigned int pio_base1_addr2 = 0x370; // Control block, ide bus 1unsigned int pio_memory_seg = 0;unsigned int pio_reg_addrs[10];unsigned char pio_last_read[10];unsigned char pio_last_write[10];static uint8 pio_inbyte(uint16 port){//	dprintf("inb 0x%x\n", pio_reg_addrs[port]);  return in8(pio_reg_addrs[port]);}static uint16 pio_inword(uint16 port){//	dprintf("inw 0x%x\n", pio_reg_addrs[port]);  return in16(pio_reg_addrs[port]);}static void	pio_outbyte(uint16 port, uint8 data){//	dprintf("outb 0x%x, 0x%x\n", pio_reg_addrs[port], data);	out8(data, pio_reg_addrs[port]);}static void	pio_rep_inword(uint16 port, uint16 *addr, unsigned long count){  __asm__ __volatile__    (     "rep ; insw" : "=D" (addr), "=c" (count) : "d" (pio_reg_addrs[port]),     "0" (addr), "1" (count)     );}static void	pio_rep_outword(uint16 port, uint16 *addr, unsigned long count){  __asm__ __volatile__    (     "rep ; outsw" : "=S" (addr), "=c" (count) : "d" (pio_reg_addrs[port]),     "0" (addr), "1" (count)     );}static void	ide_reg_poll(){	while(1)	{	  if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0)        break;	}}static bool ide_wait_busy(){  int i;  for(i=0; i<100000; i++)	{	  if((i % 10000) == 0)		  dprintf("CB_ASTAT = 0x%x\n", pio_inbyte(CB_ASTAT));      if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0)        return true;	}  return false;}static int ide_select_device(int bus, int device){	uint8		status;	int			i;	ide_device	ide = devices[(bus*2) + device];	dprintf("0a\n");	// test for a known, valid device	if(ide.device_type == (NO_DEVICE | UNKNOWN_DEVICE))      return NO_ERROR;	dprintf("0b\n");	// See if we can get it's attention	if(ide_wait_busy() == false)	  return ERR_DEV_TIMED_OUT;	// Select required device	pio_outbyte(CB_DH, device ? CB_DH_DEV1 : CB_DH_DEV0);	DELAY400NS;	for(i=0; i<10000; i++)      {		// read the device status		status = pio_inbyte(CB_STAT);		dprintf("0c status 0x%x\n", status);		if (ide.device_type == ATA_DEVICE) {		    if ((status & (CB_STAT_BSY | CB_STAT_RDY | CB_STAT_SKC))                    == (CB_STAT_RDY | CB_STAT_SKC))			  return NO_ERROR;		} else {			if ((status & CB_STAT_BSY) == 0)			  return NO_ERROR;		}      }	dprintf("0d\n");  return ERR_DEV_TIMED_OUT;}static void ide_delay(int bus, int device){	ide_device	ide = devices[(bus*2) + device];	if(ide.device_type == ATAPI_DEVICE)	  thread_snooze(1000000);	return;}static int reg_pio_data_in(int bus, int dev, int cmd, int fr, int sc,					unsigned int cyl, int head, int sect, uint8 *output,					uint16 numSect, unsigned int multiCnt){    unsigned char devHead;    unsigned char devCtrl;    unsigned char cylLow;    unsigned char cylHigh;    unsigned char status;    uint16        *buffer = (uint16*)output;  dprintf("reg_pio_data_in: bus %d dev %d cmd %d fr %d sc %d cyl %d head %d sect %d numSect %d multiCnt %d\n",  	bus, dev, cmd, fr, sc, cyl, head, sect, numSect, multiCnt);    devCtrl = CB_DC_HD15 | CB_DC_NIEN;    devHead = dev ? CB_DH_DEV1 : CB_DH_DEV0;    devHead = devHead | (head & 0x4f);    cylLow = cyl & 0x00ff;    cylHigh = (cyl & 0xff00) >> 8;    // these commands transfer only 1 sector    if(cmd == (CMD_IDENTIFY_DEVICE | CMD_IDENTIFY_DEVICE_PACKET | CMD_READ_BUFFER))      numSect = 1;    // multiCnt = 1 unless CMD_READ_MULTIPLE true    if(cmd != CMD_READ_MULTIPLE || !multiCnt)      multiCnt = 1;    // select the drive    if(ide_select_device(bus, dev) == ERR_DEV_TIMED_OUT)      return ERR_DEV_TIMED_OUT;    // set up the registers    pio_outbyte(CB_DC, devCtrl);    pio_outbyte(CB_FR, fr);    pio_outbyte(CB_SC, sc);    pio_outbyte(CB_SN, sect);    pio_outbyte(CB_CL, cylLow);    pio_outbyte(CB_CH, cylHigh);    pio_outbyte(CB_DH, devHead);    // Start the command. The drive should immediately set BUSY status.    pio_outbyte(CB_CMD, cmd);    DELAY400NS;    while(1)    {      ide_delay(bus, dev);      // ensure drive isn't still busy      ide_reg_poll();      // check status once only per read      status = pio_inbyte(CB_STAT);      if((numSect < 1) && (status & CB_STAT_DRQ))        return ERR_DEV_BUSY;      if (numSect < 1)        break;      if((status & (CB_STAT_BSY | CB_STAT_DRQ)) == CB_STAT_DRQ)      {        unsigned int wordCnt = multiCnt > numSect ? numSect : multiCnt;        wordCnt = wordCnt * 256;        pio_rep_inword(CB_DATA, buffer, wordCnt);        DELAY400NS;        numSect = numSect - multiCnt;        buffer += wordCnt;      }      // catch all possible fault conditions      if(status & CB_STAT_BSY)        return ERR_DEV_BUSY;      if(status & CB_STAT_DF)        return ERR_DEV_BUSY;      if(status & CB_STAT_ERR)        return ERR_DEV_HARDWARE_ERROR;      if((status & CB_STAT_DRQ) == 0)        return ERR_DEV_BUSY;    }    return NO_ERROR;}static int reg_pio_data_out(int bus, int dev, int cmd, int fr, int sc,			     unsigned int cyl, int head, int sect, const uint8 *output,			     uint16 numSect, unsigned int multiCnt){    unsigned char devHead;    unsigned char devCtrl;    unsigned char cylLow;    unsigned char cylHigh;    unsigned char status;    uint16		  *buffer = (uint16*)output;    devCtrl = CB_DC_HD15 | CB_DC_NIEN;    devHead = dev ? CB_DH_DEV1 : CB_DH_DEV0;    devHead = devHead | (head & 0x4f);    cylLow  = cyl & 0x00ff;    cylHigh = (cyl & 0xff00) >> 8;    if (cmd == CMD_WRITE_BUFFER)      numSect = 1;    // only Write Multiple and CFA Write Multiple W/O Erase uses multCnt    if ((cmd != CMD_WRITE_MULTIPLE) && (cmd != CMD_CFA_WRITE_MULTIPLE_WO_ERASE))      multiCnt = 1;   // select the drive    if (ide_select_device(bus, dev) != NO_ERROR)      return ERR_DEV_TIMED_OUT;	dprintf("1\n");	// set up the registers    pio_outbyte(CB_DC, devCtrl);    pio_outbyte(CB_FR, fr);    pio_outbyte(CB_SC, sc);    pio_outbyte(CB_SN, sect);    pio_outbyte(CB_CL, cylLow);    pio_outbyte(CB_CH, cylHigh);    pio_outbyte(CB_DH, devHead);    // Start the command. The drive should immediately set BUSY status.    pio_outbyte(CB_CMD, cmd);    DELAY400NS;    if (ide_wait_busy() == false)      return ERR_DEV_TIMED_OUT; 	dprintf("2\n");   status = pio_inbyte(CB_STAT);    while (1)    {      if ((status & (CB_STAT_BSY | CB_STAT_DRQ)) == CB_STAT_DRQ)      {        unsigned int wordCnt = multiCnt > numSect ? numSect : multiCnt;        wordCnt = wordCnt * 256;        pio_rep_outword(CB_DATA, buffer, wordCnt);        DELAY400NS;        numSect = numSect - multiCnt;        buffer += wordCnt;      }	dprintf("3 status 0x%x\n", status);	  // check all possible fault conditions      if(status & CB_STAT_BSY)        return ERR_DEV_BUSY;      if(status & CB_STAT_DF)        return ERR_DEV_BUSY;      if(status & CB_STAT_ERR)        return ERR_DEV_HARDWARE_ERROR;      if ((status & CB_STAT_DRQ) == 0)        return ERR_DEV_BUSY;      ide_delay(bus, dev);      // ensure drive isn't still busy      ide_reg_poll();      if(numSect < 1 && status & (CB_STAT_BSY | CB_STAT_DF | CB_STAT_ERR))        {          dprintf("reg_pio_data_out(): status = 0x%x\n", status);          return ERR_DEV_BUSY;        }    }	dprintf("4\n");    return NO_ERROR;}static void ata_block_to_chs(uint32 block, ide_device *device, int *cylinder, int *head, int *sect){  *sect = (block % device->hardware_device.sectors) + 1;  block /= device->hardware_device.sectors;  *head = (block % device->hardware_device.heads);

⌨️ 快捷键说明

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