/* send a command or parameter to the drive * Generates # of step pulses. */ static inline int ft_send_to_drive(int arg) { /* Always wait for a command_timeout period to separate * individuals commands and/or parameters. */ ftape_sleep(3 * FT_MILLISECOND); /* Keep cylinder nr within range, step towards home if possible. */ if (ftape_current_cylinder >= arg) { return fdc_seek(ftape_current_cylinder - arg); } else { return fdc_seek(ftape_current_cylinder + arg); } }
/************************************************************************** * int fdc_fdos_seek * parameter is a block number */ int fdc_fdos_seek (int where) { FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type; FDC_COMMAND_STRUCT *pCMD = &cmd; pCMD -> blnr = where ; return (fdc_seek (pCMD, pFG)); }
void fdc_read(int cyl,int head,int sect,int seccount) { //char cmd[9]={READ_DATA,head<<2,cyl,head,sect,2,seccount,0x1b,0xff}; char cmd[9]={0xe6,head<<2,cyl,head,sect,0x02,0x12,1,0xff}; for(int i=0;i<5;i++) { send_fdc_cmd(cmd,9); while(!fdc_inted)io_hlt(); fdc_inted=false; char res[7]; get_fdc_cmd(res,7); int result=check_st0(res[0]); if(result == 0)break; fdc_recalibrate(); fdc_seek(cyl,head); } }
/* --- Main FDC dispatcher --- */ static void fdc_execute(FDC_765 *self) { /* This code to dump out FDC commands as they are received is very useful * in debugging * * */ int NC; fdc_dprintf(5, "FDC: "); for (NC = 0; NC < bytes_in_cmd[self->fdc_cmd_buf[0] & 0x1F]; NC++) fdc_dprintf(5, "%02x ", self->fdc_cmd_buf[NC]); fdc_dprintf(5, "\n"); /* */ /* Check if the DOR (ugh!) is being used to force us to a different drive. */ fdc_dorcheck(self); /* Reset "seek finished" flag */ self->fdc_st0 &= 0xBF; switch(self->fdc_cmd_buf[0] & 0x1F) { case 2: fdc_read_track(self); break; /* 2: READ TRACK */ case 3: fdc_specify(self); break; /* 3: SPECIFY */ case 4: fdc_sense_drive(self); break; /* 4: SENSE DRV STATUS*/ case 5: fdc_write(self, 0); break; /* 5: WRITE */ case 6: fdc_read(self, 0); break; /* 6: READ */ case 7: fdc_recalibrate(self); break; /* 7: RECALIBRATE */ case 8: fdc_sense_int(self); break; /* 8: SENSE INT STATUS*/ case 9: fdc_write(self, 1); break; /* 9: WRITE DELETED */ case 10:fdc_read_id(self); break; /*10: READ ID */ case 12:fdc_read(self, 1); break; /*12: READ DELETED */ case 13:fdc_format(self); break; /*13: FORMAT TRACK */ case 15:fdc_seek(self); break; /*15: SEEK */ case 17: /*17: SCAN EQUAL */ case 25: /*25: SCAN LOW/EQUAL */ case 30:fdc_scan(self); break; /*30: SCAN HIGH/EQUAL*/ default: fdc_dprintf(2, "Unknown FDC command %d\n", self->fdc_cmd_buf[0] & 0x1F); fdc_error(self); break; } }
/* Scan all drives and check if drive is present and disk is inserted */ int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) { int i,drives,state; /* OK procedure of data book is satisfied. * trying to get some information over the drives */ state=0; /* no drives, no disks */ for(drives=0;drives<4;drives++) { pCMD->drive=drives; select_fdc_drive(pCMD); pCMD->blnr=0; /* set to the 1st block */ if(fdc_recalibrate(pCMD,pFG)==FALSE) continue; if((pCMD->result[STATUS_0]&0x10)==0x10) continue; /* ok drive connected check for disk */ state|=(1<<drives); pCMD->blnr=pFG->size; /* set to the last block */ if(fdc_seek(pCMD,pFG)==FALSE) continue; pCMD->blnr=0; /* set to the 1st block */ if(fdc_recalibrate(pCMD,pFG)==FALSE) continue; pCMD->cmd[COMMAND]=FDC_CMD_READ_ID; if(fdc_issue_cmd(pCMD,pFG)==FALSE) continue; state|=(0x10<<drives); } stop_fdc_drive(pCMD); for(i=0;i<4;i++) { PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i, ((state&(1<<i))==(1<<i)) ? "":"not ", ((state&(0x10<<i))==(0x10<<i)) ? "":"no ", ((state&(0x10<<i))==(0x10<<i)) ? pFG->name : ""); } pCMD->flags=state; return TRUE; }
/* reads data from FDC, seek commands are issued automatic */ int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) { /* first seek to start address */ unsigned long len,lastblk,readblk,i,timeout,ii,offset; unsigned char pcn,c,retriesrw,retriescal; unsigned char *bufferw; /* working buffer */ int sect_size; int flags; flags=disable_interrupts(); /* switch off all Interrupts */ select_fdc_drive(pCMD); /* switch on drive */ sect_size=0x080<<pFG->sect_code; retriesrw=0; retriescal=0; offset=0; if(fdc_seek(pCMD,pFG)==FALSE) { stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } if((pCMD->result[STATUS_0]&0x20)!=0x20) { printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]); stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } pcn=pCMD->result[STATUS_PCN]; /* current track */ /* now determine the next seek point */ lastblk=pCMD->blnr + blocks; /* readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */ readblk=pFG->sect-(pCMD->blnr%pFG->sect); PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr); if(readblk>blocks) /* is end within 1st track */ readblk=blocks; /* yes, correct it */ PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr); bufferw=&buffer[0]; /* setup working buffer */ do { retryrw: len=sect_size * readblk; pCMD->cmd[COMMAND]=FDC_CMD_READ; if(fdc_issue_cmd(pCMD,pFG)==FALSE) { stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } for (i=0;i<len;i++) { timeout=FDC_TIME_OUT; do { c=read_fdc_reg(FDC_MSR); if((c&0xC0)==0xC0) { bufferw[i]=read_fdc_reg(FDC_FIFO); break; } if((c&0xC0)==0x80) { /* output */ PRINTF("Transfer error transfered: at %ld, MSR=%02X\n",i,c); if(i>6) { for(ii=0;ii<7;ii++) { pCMD->result[ii]=bufferw[(i-7+ii)]; } /* for */ } if(retriesrw++>FDC_RW_RETRIES) { if (retriescal++>FDC_CAL_RETRIES) { stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } else { PRINTF(" trying to recalibrate Try %d\n",retriescal); if(fdc_recalibrate(pCMD,pFG)==FALSE) { stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } retriesrw=0; goto retrycal; } /* else >FDC_CAL_RETRIES */ } else { PRINTF("Read retry %d\n",retriesrw); goto retryrw; } /* else >FDC_RW_RETRIES */ }/* if output */ timeout--; }while(TRUE); } /* for len */ /* the last sector of a track or all data has been read, * we need to get the results */ fdc_terminate(pCMD); offset+=(sect_size*readblk); /* set up buffer pointer */ bufferw=&buffer[offset]; pCMD->blnr+=readblk; /* update current block nr */ blocks-=readblk; /* update blocks */ if(blocks==0) break; /* we are finish */ /* setup new read blocks */ /* readblk=pFG->head*pFG->sect; */ readblk=pFG->sect; if(readblk>blocks) readblk=blocks; retrycal: /* a seek is necessary */ if(fdc_seek(pCMD,pFG)==FALSE) { stop_fdc_drive(pCMD); enable_interrupts(); return FALSE; } if((pCMD->result[STATUS_0]&0x20)!=0x20) { PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]); stop_fdc_drive(pCMD); return FALSE; } pcn=pCMD->result[STATUS_PCN]; /* current track */ }while(TRUE); /* start over */ stop_fdc_drive(pCMD); /* switch off drive */ enable_interrupts(); return TRUE; }
void fdc_recalib(void) { FDC.command[CMD_C] = 0; // seek to track 0 fdc_seek(); }
void t_FDC::fdc_recalib() { command[CMD_C] = 0; // seek to track 0 fdc_seek(); }
void fdc_write(unsigned char a) { // Write byte to data register static int cmdlen = 9; // length of FDC command #ifdef FDC_DEBUG printf("FDC DATA WRITE = 0x%x\n", a); #endif switch(phase) { case P_COMMAND: fdccommand[CmdByte] = a; // store part of command if (CmdByte == 0) { // first byte of command switch(a&0x1F) { case CMD_READDATA: case CMD_READDELETEDDATA: case CMD_WRITEDATA: case CMD_WRITEDELETEDDATA: case CMD_READDIAGNOSTIC: case CMD_SCANEQUAL: case CMD_SCANLOWEQUAL: case CMD_SCANHIGHEQUAL: cmdlen = 9; break; case CMD_WRITEID: cmdlen = 6; break; case CMD_SPECIFY: case CMD_SEEK: cmdlen = 3; break; case CMD_READID: case CMD_RECALIBRATE: case CMD_SENSEDRV: cmdlen = 2; break; case CMD_SENSEINT: case CMD_VERSION: cmdlen = 1; break; default: // Invalid Command cmdlen = 1; printf("Invalid FDC Command received: 0x%x\n", a); break; } // Set CB (Busy) flag //fdc_status_main|=MAIN_CB; } CmdByte++; if (CmdByte == cmdlen) { // Command phase finished switch(fdccommand[0]&0x1F) { case CMD_READDATA: fdc_read_data(); break; case CMD_READDELETEDDATA: printf("*** Unimplemented FDC Command READ DELETED DATA\n"); break; case CMD_WRITEDATA: printf("*** Unimplemented FDC Command WRITE DATA\n"); break; case CMD_WRITEDELETEDDATA: printf("*** Unimplemented FDC Command WRITE DELETED DATA\n"); break; case CMD_READDIAGNOSTIC: printf("*** Unimplemented FDC Command READ DIAGNOSTIC\n"); break; case CMD_READID: // Read sector ID fdc_read_id(); break; case CMD_WRITEID: printf("*** Unimplemented FDC Command WRITE ID\n"); break; case CMD_SCANEQUAL: printf("*** Unimplemented FDC Command SCAN EQUAL\n"); break; case CMD_SCANLOWEQUAL: printf("*** Unimplemented FDC Command SCAN LOW OR EQUAL\n"); break; case CMD_SCANHIGHEQUAL: printf("*** Unimplemented FDC Command SCAN HIGH OR EQUAL\n"); break; case CMD_RECALIBRATE: // Reset to track 0 fdc_seek(0); break; case CMD_SENSEINT: // Get Interrupt status register fdc_senseint(); break; case CMD_SPECIFY: // We really don't need to do anything here. This command only sets // physical timing parameters. These are not relevant to a virtual FDC. fdc_status_main&=~MAIN_CB; // Clear CB (busy) flag break; case CMD_SENSEDRV: printf("*** Unimplemented FDC Command SENSE DRIVE\n"); break; case CMD_VERSION: printf("*** Unimplemented FDC Command VERSION\n"); break; case CMD_SEEK: // Seek to a specified track fdc_seek(fdccommand[2]); break; default: break; } CmdByte = 0; } break; case P_EXECUTION: // Execution phase break; case P_RESULT: // There should be no write acces in result phase break; } }
/* If no request is currently being processed and there's new requests in the queue, process the first one. This can be called from an interrupt or the normal kernel context. */ void do_request(blkreq_t *req) { fd_dev_t *dev; u_long track, sect, cyl, head, big_sect, sects; u_long flags; int i; save_flags(flags); /* This label is used to eliminate tail-recursion. */ top: cli(); if(current_req != NULL) { if(req != NULL) append_node(&fd_reqs, &req->node); load_flags(flags); return; } for(i = 0; i < 2; i++) { if(fd_devs[i].recalibrate) { fdc_recal(&fd_devs[i]); if(req != NULL) append_node(&fd_reqs, &req->node); load_flags(flags); return; } } if(req == NULL) { if(!list_empty_p(&fd_reqs)) { req = (blkreq_t *)fd_reqs.head; remove_node(&req->node); } else { load_flags(flags); return; } } current_req = req; #if 0 req->retries = 0; #endif load_flags(flags); dev = REQ_FD_DEV(req); DB(("fd:do_request: req=%p drive=%d block=%d nblocks=%d cmd=%d buf=%p\n", req, dev->drvno, req->block, req->nblocks, req->command, req->buf)); switch(req->command) { case FD_CMD_SEEK: /* We wanna MOVE DA HEAD! */ /* Do da seek. */ if(fdc_seek(dev, req->block) == FALSE) { handle_error("FD_CMD_SEEK, seek"); goto top; break; } /* Then Sense Interrupt Status */ if(fdc_sense() == FALSE) { handle_error("FD_CMD_SEEK, fdc_sense"); goto top; break; } /* and now we have to Read the ID */ if(fdc_read_id(dev) == FALSE) { handle_error("FD_CMD_SEEK, read_id"); goto top; break; } fd_end_request(0); req = NULL; goto top; case FD_CMD_TIMER: fd_end_request(0); req = NULL; goto top; } if(req->block >= dev->total_blocks) { kprintf("fd: Device %s (%p) doesn't have a block %d!\n", dev->name, dev, req->block); fd_end_request(-1); req = NULL; goto top; } big_sect = req->block; sects = req->nblocks; track = big_sect / dev->disk_p->sectors; sect = big_sect % dev->disk_p->sectors + 1; head = track % dev->disk_p->heads; cyl = track / dev->disk_p->heads; DB(("fd:do_request: cyl=%d sect=%d head=%d sects=%d\n", cyl, sect, head, sects)); switch(req->command) { case FD_CMD_READ: /* We wanna READ the floppy! */ #if 0 fd_end_request(0); req = NULL; goto top; #endif /* We need to seek to the right cylinder. */ if(fdc_seek(dev, cyl) == FALSE) { handle_error("FD_CMD_READ, seek"); goto top; break; } /* Then Sense Interrupt Status */ if(fdc_sense() == FALSE) { handle_error("FD_CMD_READ, fdc_sense"); goto top; break; } /* and now we have to Read the ID */ if(fdc_read_id(dev) == FALSE) { handle_error("FD_CMD_READ, read_id"); goto top; break; } #define TPA(XX) ((u_long)TO_PHYSICAL(XX)) /* Tell the DMA what to do, and hope for the best! */ /* Should move this inside fdc, in fdc_read() i think */ DMAbuf.Buffer = track_buf; DMAbuf.Page = (u_int8)((TPA(track_buf) >> 16) & 0xff); DMAbuf.Offset = (u_int16)(TPA(track_buf) & 0xffff); DMAbuf.Len = (u_int16)(dev->disk_p->sectors * dev->disk_p->heads * FD_SECTSIZ) - 1; DMAbuf.Chan = FLOPPY_DMA; kernel->setup_dma(&DMAbuf, DMA_READ); /* Now we issue a read command. */ if(fdc_read(dev, cyl) == FALSE) { handle_error("FD_CMD_READ, read"); goto top; break; } break; case FD_CMD_WRITE: /* We wanna WRITE it too! */ fd_end_request(0); req = NULL; goto top; default: kprintf("fd:do_request: Unknown command in fd_req, %d\n", req->command); fd_end_request(-1); req = NULL; goto top; } }