📄 cmd_fdc.c
字号:
/* * (C) Copyright 2001 * Denis Peter, MPL AG, d.peter@mpl.ch. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * *//* * Floppy Disk support */#include <common.h>#include <config.h>#include <command.h>#include <image.h>#undef FDC_DEBUG#ifdef FDC_DEBUG#define PRINTF(fmt,args...) printf (fmt ,##args)#else#define PRINTF(fmt,args...)#endif#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif/*#if (CONFIG_COMMANDS & CFG_CMD_DATE) *//*#include <rtc.h> *//*#endif */#if ((CONFIG_COMMANDS & CFG_CMD_FDC) || (CONFIG_COMMANDS & CFG_CMD_FDOS))typedef struct { int flags; /* connected drives ect */ unsigned long blnr; /* Logical block nr */ uchar drive; /* drive no */ uchar cmdlen; /* cmd length */ uchar cmd[16]; /* cmd desc */ uchar dma; /* if > 0 dma enabled */ uchar result[11];/* status information */ uchar resultlen; /* lenght of result */} FDC_COMMAND_STRUCT;/* flags: only the lower 8bit used: * bit 0 if set drive 0 is present * bit 1 if set drive 1 is present * bit 2 if set drive 2 is present * bit 3 if set drive 3 is present * bit 4 if set disk in drive 0 is inserted * bit 5 if set disk in drive 1 is inserted * bit 6 if set disk in drive 2 is inserted * bit 7 if set disk in drive 4 is inserted *//* cmd indexes */#define COMMAND 0#define DRIVE 1#define CONFIG0 1#define SPEC_HUTSRT 1#define TRACK 2#define CONFIG1 2#define SPEC_HLT 2#define HEAD 3#define CONFIG2 3#define SECTOR 4#define SECTOR_SIZE 5#define LAST_TRACK 6#define GAP 7#define DTL 8/* result indexes */#define STATUS_0 0#define STATUS_PCN 1#define STATUS_1 1#define STATUS_2 2#define STATUS_TRACK 3#define STATUS_HEAD 4#define STATUS_SECT 5#define STATUS_SECT_SIZE 6/* Register addresses */#define FDC_BASE 0x3F0#define FDC_SRA FDC_BASE + 0 /* Status Register A */#define FDC_SRB FDC_BASE + 1 /* Status Register B */#define FDC_DOR FDC_BASE + 2 /* Digital Output Register */#define FDC_TDR FDC_BASE + 3 /* Tape Drive Register */#define FDC_DSR FDC_BASE + 4 /* Data rate Register */#define FDC_MSR FDC_BASE + 4 /* Main Status Register */#define FDC_FIFO FDC_BASE + 5 /* FIFO */#define FDC_DIR FDC_BASE + 6 /* Digital Input Register */#define FDC_CCR FDC_BASE + 7 /* Configuration Control *//* Commands */#define FDC_CMD_SENSE_INT 0x08#define FDC_CMD_CONFIGURE 0x13#define FDC_CMD_SPECIFY 0x03#define FDC_CMD_RECALIBRATE 0x07#define FDC_CMD_READ 0x06#define FDC_CMD_READ_TRACK 0x02#define FDC_CMD_READ_ID 0x0A#define FDC_CMD_DUMP_REG 0x0E#define FDC_CMD_SEEK 0x0F#define FDC_CMD_SENSE_INT_LEN 0x01#define FDC_CMD_CONFIGURE_LEN 0x04#define FDC_CMD_SPECIFY_LEN 0x03#define FDC_CMD_RECALIBRATE_LEN 0x02#define FDC_CMD_READ_LEN 0x09#define FDC_CMD_READ_TRACK_LEN 0x09#define FDC_CMD_READ_ID_LEN 0x02#define FDC_CMD_DUMP_REG_LEN 0x01#define FDC_CMD_SEEK_LEN 0x03#define FDC_FIFO_THR 0x0C#define FDC_FIFO_DIS 0x00#define FDC_IMPLIED_SEEK 0x01#define FDC_POLL_DIS 0x00#define FDC_PRE_TRK 0x00#define FDC_CONFIGURE FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)#define FDC_MFM_MODE 0x01 /* MFM enable */#define FDC_SKIP_MODE 0x00 /* skip enable */#define FDC_TIME_OUT 100000 /* time out */#define FDC_RW_RETRIES 3 /* read write retries */#define FDC_CAL_RETRIES 3 /* calibration and seek retries *//* Disk structure */typedef struct { unsigned int size; /* nr of sectors total */ unsigned int sect; /* sectors per track */ unsigned int head; /* nr of heads */ unsigned int track; /* nr of tracks */ unsigned int stretch; /* !=0 means double track steps */ unsigned char gap; /* gap1 size */ unsigned char rate; /* data rate. |= 0x40 for perpendicular */ unsigned char spec1; /* stepping rate, head unload time */ unsigned char fmt_gap; /* gap2 size */ unsigned char hlt; /* head load time */ unsigned char sect_code; /* Sector Size code */ const char * name; /* used only for predefined formats */} FD_GEO_STRUCT;/* supported Floppy types (currently only one) */const static FD_GEO_STRUCT floppy_type[2] = { { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" }, /* 7 1.44MB 3.5" */ { 0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL }, /* end of table */};static FDC_COMMAND_STRUCT cmd; /* global command struct *//* If the boot drive number is undefined, we assume it's drive 0 */#ifndef CFG_FDC_DRIVE_NUMBER#define CFG_FDC_DRIVE_NUMBER 0#endif/* Hardware access */#ifndef CFG_ISA_IO_STRIDE#define CFG_ISA_IO_STRIDE 1#endif#ifndef CFG_ISA_IO_OFFSET#define CFG_ISA_IO_OFFSET 0#endif#ifdef CONFIG_AMIGAONEG3SEunsigned char INT6_Status;void fdc_interrupt(void){ INT6_Status = 0x80;}/* waits for an interrupt (polling) */int wait_for_fdc_int(void){ unsigned long timeout; timeout = FDC_TIME_OUT; while(((volatile)INT6_Status & 0x80) == 0) { timeout--; udelay(10); if(timeout == 0) /* timeout occured */ return FALSE; } INT6_Status = 0; return TRUE;}#endif/* Supporting Functions *//* reads a Register of the FDC */unsigned char read_fdc_reg(unsigned int addr){ volatile unsigned char *val = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + (addr * CFG_ISA_IO_STRIDE) + CFG_ISA_IO_OFFSET); return val [0];}/* writes a Register of the FDC */void write_fdc_reg(unsigned int addr, unsigned char val){ volatile unsigned char *tmp = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS + (addr * CFG_ISA_IO_STRIDE) + CFG_ISA_IO_OFFSET); tmp[0]=val;}#ifndef CONFIG_AMIGAONEG3SE/* waits for an interrupt (polling) */int wait_for_fdc_int(void){ unsigned long timeout; timeout = FDC_TIME_OUT; while((read_fdc_reg(FDC_SRA)&0x80)==0) { timeout--; udelay(10); if(timeout==0) /* timeout occured */ return FALSE; } return TRUE;}#endif/* reads a byte from the FIFO of the FDC and checks direction and RQM bit of the MSR. returns -1 if timeout, or byte if ok */int read_fdc_byte(void){ unsigned long timeout; timeout = FDC_TIME_OUT; while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) { /* direction out and ready */ udelay(10); timeout--; if(timeout==0) /* timeout occured */ return -1; } return read_fdc_reg(FDC_FIFO);}/* if the direction of the FIFO is wrong, this routine is used to empty the FIFO. Should _not_ be used */int fdc_need_more_output(void){ unsigned char c; while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0) { c=(unsigned char)read_fdc_byte(); printf("Error: more output: %x\n",c); } return TRUE;}/* writes a byte to the FIFO of the FDC and checks direction and RQM bit of the MSR */int write_fdc_byte(unsigned char val){ unsigned long timeout; timeout = FDC_TIME_OUT; while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) { /* direction in and ready for byte */ timeout--; udelay(10); fdc_need_more_output(); if(timeout==0) /* timeout occured */ return FALSE; } write_fdc_reg(FDC_FIFO,val); return TRUE;}/* sets up all FDC commands and issues it to the FDC. If the command causes direct results (no Execution Phase) the result is be read as well. */int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG){ int i; unsigned long head,track,sect,timeout; track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */ sect = pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */ head = sect / pFG->sect; /* head nr */ sect = sect % pFG->sect; /* remaining blocks */ sect++; /* sectors are 1 based */ PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n", pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr); if(head|=0) { /* max heads = 2 */ pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */ pCMD->cmd[HEAD]=(unsigned char) head; /* head register */ } else { pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */ pCMD->cmd[HEAD]=(unsigned char) head; /* head register */ } pCMD->cmd[TRACK]=(unsigned char) track; /* track */ switch (pCMD->cmd[COMMAND]) { case FDC_CMD_READ: pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */ pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */ pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */ pCMD->cmd[GAP]=pFG->gap; /* gap */ pCMD->cmd[DTL]=0xFF; /* DTL */ pCMD->cmdlen=FDC_CMD_READ_LEN; pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */ pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */ pCMD->resultlen=0; /* result only after execution */ break; case FDC_CMD_SEEK: pCMD->cmdlen=FDC_CMD_SEEK_LEN; pCMD->resultlen=0; /* no result */ break; case FDC_CMD_CONFIGURE: pCMD->cmd[CONFIG0]=0; pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */ pCMD->cmd[CONFIG2]=FDC_PRE_TRK; /* Precompensation Track */ pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN; pCMD->resultlen=0; /* no result */ break; case FDC_CMD_SPECIFY: pCMD->cmd[SPEC_HUTSRT]=pFG->spec1; pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */ if(pCMD->dma==0) pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */ pCMD->cmdlen=FDC_CMD_SPECIFY_LEN; pCMD->resultlen=0; /* no result */ break; case FDC_CMD_DUMP_REG: pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN; pCMD->resultlen=10; /* 10 byte result */ break; case FDC_CMD_READ_ID: pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */ pCMD->cmdlen=FDC_CMD_READ_ID_LEN; pCMD->resultlen=7; /* 7 byte result */ break; case FDC_CMD_RECALIBRATE: pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */ pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN; pCMD->resultlen=0; /* no result */ break; break; case FDC_CMD_SENSE_INT: pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN; pCMD->resultlen=2; break; } for(i=0;i<pCMD->cmdlen;i++) { /* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */ if(write_fdc_byte(pCMD->cmd[i])==FALSE) { PRINTF("Error: timeout while issue cmd%d\n",i); return FALSE; } } timeout=FDC_TIME_OUT; for(i=0;i<pCMD->resultlen;i++) { while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) { timeout--; if(timeout==0) { PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR)); return FALSE; } } pCMD->result[i]=(unsigned char)read_fdc_byte(); } return TRUE;}/* selects the drive assigned in the cmd structur and switches on the Motor */void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD){ unsigned char val; val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */ if((read_fdc_reg(FDC_DOR)&val)!=val) { write_fdc_reg(FDC_DOR,val); for(val=0;val<255;val++) udelay(500); /* wait some time to start motor */ }}/* switches off the Motor of the specified drive */void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD){ unsigned char val; val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */ write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));}/* issues a recalibrate command, waits for interrupt and * issues a sense_interrupt */int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG){ pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE; if(fdc_issue_cmd(pCMD,pFG)==FALSE) return FALSE; while(wait_for_fdc_int()!=TRUE); pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT; return(fdc_issue_cmd(pCMD,pFG));}/* issues a recalibrate command, waits for interrupt and * issues a sense_interrupt */int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG){ pCMD->cmd[COMMAND]=FDC_CMD_SEEK; if(fdc_issue_cmd(pCMD,pFG)==FALSE) return FALSE; while(wait_for_fdc_int()!=TRUE); pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT; return(fdc_issue_cmd(pCMD,pFG));}#ifndef CONFIG_AMIGAONEG3SE/* terminates current command, by not servicing the FIFO * waits for interrupt and fills in the result bytes */int fdc_terminate(FDC_COMMAND_STRUCT *pCMD){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -