📄 fdc.c
字号:
* reads a complete track starting at sector 1 * for nsects, assumes that drive selection and * side selection are already performed */ short cerr;#ifdef EXBUF register short count = 0, sect, err = 0; char addr[20]; while(count < 10){ if(cerr = read_addr(addr)){ err = cerr;printf("Deverr: Read address error %x\n",cerr); count++; } else{ sect = addr[2] + 1; /* sector number */ sect = (sect > nsects)? sect - nsects:sect; cerr = read_sect(buffer + (SIZE * (sect - 1)),sect,nsects - sect + 1,0); if(sect != 1) cerr |= read_sect(buffer,1,sect - 1,0); if(cerr){ err = cerr; count++; } else break; } }#else register short count = 0,err; while(count < 10){ if(cerr = read_sect(buffer,1,nsects,0)){ err = cerr; count++; } else break; }#endif EXBUF if(err) fdcerror = err; return count;}tr_write(buffer,nsects)char *buffer;short nsects;{ /* * writes a complete track starting at sector 1 * for nsects, assumes that drive selection and * side selection are already performed */ short cerr;#ifdef EXBUF register short count = 0, sect, err = 0; char addr[20]; while(count < 10){ if(cerr = read_addr(addr)){ err = cerr; count++; } else{ sect = addr[2] + 1; /* sector number */ sect = (sect > nsects)? sect - nsects:sect; cerr = write_sect(buffer + (SIZE * (sect - 1)),sect,nsects - sect + 1,0); if(sect != 1) cerr |= write_sect(buffer,1,sect - 1,0); if(cerr){ err = cerr; count++; } else break; } }#else register count = 0,err; while(count < 10){ if(cerr = write_sect(buffer,1,nsects,0)){ err = cerr; count++; } else break; }#endif EXBUF if(err) fdcerror = err; return count;}oldest(aged)short aged;{ /* * makes the buffer age aged to become * the oldest and adjust all the buffers * that were older than it to become 1 * younger returns the array index of the oldest */ register short p = 0, newone; while(p < NO_BUFS){ if(fdb[p].age >= aged){ if(fdb[p].age == aged){ newone = p; fdb[p].age = NO_BUFS; } fdb[p].age--; } p++; } return newone;}youngest(aged)short aged;{ /* * makes the buffer age aged to become * the youngest and adjust all the buffers * that were younger than it to become 1 * older returns the array index of the youngest */ register short p = 0, newone; while(p < NO_BUFS){ if(fdb[p].age <= aged){ if(fdb[p].age == aged){ newone = p; fdb[p].age = -1; } fdb[p].age++; } p++; } return newone;}/* * Deverr - general error message */deverr(str, count, buf)char *str;struct buf *buf;{ printf("\n\rDeverr: "); if (count >= 10) printf("Fatal\007 "); else if (count > 1) printf("%d of ", count); printf("%s at blk %d on %d, FDC error: %x\n", str, buf->b_bno, buf->b_dev,fdcerror); return;}doseek(trk, twostep)int trk;char twostep;{ register short count = 0,err; if(twostep){ while((err = raw_seek(trk)) && count < 10){ restor(0); fdcerror = err; count++; } } else { while((err = ver_seek(trk)) && count < 10){ restor(0); fdcerror = err; count++; } } return count;}/* * ioctl for floppies, allows reading and writing of * tracks (for formatting or weird disk reads) and * reading of address fields (God knows what to use that for!) */fdioctl(dev,req,args)int dev,req;struct fdcntrl *args;{ int (*func)(); register char *emsg; register short reps; register struct drive_info *fds; int track; int write_track(), read_track(), read_addr(); dtype = fdstatus[dev & 0x3].d_type; tmpb.b_bno = -1; /* allows us to use deverr for error reports */ tmpb.b_dev = dev; /* " " " " */ /* select dev */ if (select(dev & 0x3) == ERROR){ deverr("dev not ready", 1, &tmpb); return ERROR; } switch(req){ default: /* simply return when an uknown ioctl appears */ printf("\n\rUNKNOW Ioctl for floppy, %x\n\r",req); return NOERROR;#ifdef FULLBUFFERING case TIOCFLUSH: /* flush all buffers that are dirty on this device and make them available */ return flushall(dev); /* NOTREACHED */ break;#else case TIOCFLUSH: return 0;#endif FULLBUFFERING case WRITETRACK: func = write_track; emsg = "write track:"; break; case READTRACK: func = read_track; emsg = "read track:"; break; case READADDR: func = read_addr; emsg = "read addr:"; break; case MULTIREAD: func = tr_read; emsg = "mutli read"; break; case MULTIWRITE: func = tr_write; emsg = "multi write"; break; case WRITESECT: func = write_sect; emsg = "Write sect"; break; case READSECT: func = read_sect; emsg = "Read sect"; break; } switch(req){ case READADDR: case READTRACK: case WRITETRACK: /* raw operator, possibly on a raw disk that has lost formatting info so seek with no verify etc */ /* find current position */ fds = &fdstatus[dev & 0x3]; /* Gets floppy drive track number */ if(fds->d_type & DTYPE40) track = args->trackno * 2; else track = args->trackno; if ((set_track(fds->d_curtrk)) != track){ /* raw_seek simply seeks from where ever it thinks the head is to the track specified no error checking, no verify so the head postion had better be right! */ raw_seek(track); } fds->d_curtrk = track; set_track(args->trackno); /* Sets real track 40/80 */ side(args->sideno); /* side select */ reps = raw_tr_op(args->buffer,func); break; case MULTIREAD: case MULTIWRITE: /* reads or writes the track as multiple sectors, disk MUST be formatted for this to work */ /* setup the disk, because the diskset routine uses the track value to decide on which side as well, this kludge allows diskset to not only seek to the correct track but also do side selection too */ fds = &fdstatus[dev & 0x3]; /* Gets floppy drive track number */ if(fds->d_type & DTYPESS) track = args->trackno; else track = (args->trackno * 2) + args->sideno; fdcerror = reps = diskset(&tmpb, track); if(reps == ERROR) return ERROR; reps = (*func)(args->buffer,P_TRK); break; case READSECT: case WRITESECT: /* reads or writes the track as multiple sectors, disk MUST be formatted for this to work */ /* setup the disk, because the diskset routine uses the track value to decide on which side as well, this kludge allows diskset to not only seek to the correct track but also do side selection too */ fds = &fdstatus[dev & 0x3]; /* Gets floppy drive track number */ if(fds->d_type & DTYPESS) track = args->trackno; else track = (args->trackno * 2) + args->sideno; fdcerror = reps = diskset(&tmpb, track); if(reps == ERROR) return ERROR; fdcerror = reps = (*func)(args->buffer,args->sect, 1, 0); break; } if(reps){ deverr(emsg,reps,&tmpb); if(reps >= 10) return ERROR; else return NOERROR; } return 0;}raw_tr_op(b,fn)char *b;int (*fn)();{ /* writes or reads a track/address field with the data in b */ register short count = 0,err; while(count < 10){ if(err = (*fn)(b)){ fdcerror = err; count++; } else break; } return count;}#ifdef FULLBUFFERING flush1(p)short p;{ /* given a track buffer number p this flushes it to the correct disk if it can and does nowt else */ short reps; /* to be able to use diskset we set up a buffer with info from the track buffer we are flushing */ tmpb.b_dev = fdb[p].d_minor; tmpb.b_bno = fdb[p].bstart; if(diskset(&tmpb,NOTATRACK) == ERROR) return ERROR; else{ mode = fdstatus[drive & 0x3].d_type; reps = tr_write(fdb[p].fdata,P_TRK); if(reps){ deverr("track flush",reps,&tmpb); if(reps >= 10){ /* at the mo do nothing with fatal track errors */ return ERROR; } } return NOERROR; } }flushall(dev)int dev;{ /* walk thru all the buffers flushing all those that are relevant to this device and are recently written */ register short p = 0; while(p < NO_BUFS){ /* release all the allocated buffers */ if((fdb[p].d_minor == dev) && (fdb[p].type & WRITTEN)) /* attempt to flush a dirty buffer */ if(flush1(p) == ERROR) /* Oh well it was a good try for the mo leave its state alone */ return ERROR; else{ /* succeeded in the flush now make it the oldest but leave it with a READABLE flag */ fdb[p].type &= ~WRITTEN; oldest(fdb[p].age); } p++; } return NOERROR;}#endif FULLBUFFERING
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -