|
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:118,127 –
1999/0423/sys/src/9/alphapc/devfloppy.c:118,125
(short | long)
|
|
1999/0415
| |
static void
fldump(void)
{
mb();
DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
inb(Pdor), inb(Pmsr), inb(Pdir));
mb();
}
/*
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:146,153 –
1999/0423/sys/src/9/alphapc/devfloppy.c:144,149
|
|
1999/0415
| |
FDrive *dp;
FType *t;
ulong maxtsize;
dmainit(DMAchan);
floppysetup0(&fl);
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:163,168 –
1999/0423/sys/src/9/alphapc/devfloppy.c:159,166
|
|
1999/0415
| |
maxtsize = t->tsize;
}
|
|
1999/0423
| |
dmainit(DMAchan, maxtsize);
|
|
1999/0415
| |
/*
* allocate the drive storage
*/
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:174,182 –
1999/0423/sys/src/9/alphapc/devfloppy.c:172,178
|
|
1999/0415
| |
*/
fl.motor = 0;
delay(10);
mb();
outb(Pdor, fl.motor | Fintena | Fena);
mb();
delay(10);
/*
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:267,275 –
1999/0423/sys/src/9/alphapc/devfloppy.c:263,269
|
|
1999/0415
| |
/*
* if floppy has changed or first time through
*/
mb();
if((inb(Pdir)&Fchange) || dp->vers == 0){
mb();
DPRINT("changed\n");
fldump();
dp->vers++;
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:276,289 –
1999/0423/sys/src/9/alphapc/devfloppy.c:270,277
|
|
1999/0415
| |
floppysetdef(dp);
start = dp->t;
dp->confused = 1; /* make floppyon recal */
DPRINT("b4 floppyon:\n");
fldump();
floppyon(dp);
DPRINT("after floppyon:\n");
fldump();
floppyseek(dp, dp->t->heads*dp->t->tsize);
DPRINT("after floppyseek:\n");
fldump();
while(waserror()){
while(++dp->t){
if(dp->t == &floppytype[nelem(floppytype)])
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:486,494 –
1999/0423/sys/src/9/alphapc/devfloppy.c:474,480
|
|
1999/0415
| |
/* start motor and select drive */
alreadyon = fl.motor & MOTORBIT(dp->dev);
fl.motor |= MOTORBIT(dp->dev);
mb();
outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
mb();
if(!alreadyon){
/* wait for drive to spin up */
tsleep(&dp->r, return0, 0, 750);
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:500,508 –
1999/0423/sys/src/9/alphapc/devfloppy.c:486,492
|
|
1999/0415
| |
/* set transfer rate */
if(fl.rate != dp->t->rate){
fl.rate = dp->t->rate;
mb();
outb(Pdsr, fl.rate);
mb();
}
/* get drive to a known cylinder */
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:521,529 –
1999/0423/sys/src/9/alphapc/devfloppy.c:505,511
|
|
1999/0415
| |
floppyoff(FDrive *dp)
{
fl.motor &= ~MOTORBIT(dp->dev);
mb();
outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
mb();
}
/*
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:538,547 –
1999/0423/sys/src/9/alphapc/devfloppy.c:520,527
|
|
1999/0415
| |
fl.nstat = 0;
for(i = 0; i < fl.ncmd; i++){
for(tries = 0; ; tries++){
mb();
if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
break;
mb();
if(tries > 1000){
DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
fldump();
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:552,560 –
1999/0423/sys/src/9/alphapc/devfloppy.c:532,538
|
|
1999/0415
| |
}
microdelay(8); /* for machine independence */
}
mb();
outb(Pfdata, fl.cmd[i]);
mb();
}
return 0;
}
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:576,584 –
1999/0423/sys/src/9/alphapc/devfloppy.c:554,560
|
|
1999/0415
| |
for(i = 0; i < sizeof(fl.stat); i++){
/* wait for status byte */
for(tries = 0; ; tries++){
mb();
s = inb(Pmsr)&(Ffrom|Fready);
mb();
if(s == Fready){
fl.nstat = i;
return fl.nstat;
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:593,602 –
1999/0423/sys/src/9/alphapc/devfloppy.c:569,575
|
|
1999/0415
| |
}
microdelay(8); /* for machine independence */
}
mb();
fl.stat[i] = inb(Pfdata);
mb();
// print("stat[%d]: %.2ux\n", i, fl.stat[i]);
}
fl.nstat = sizeof(fl.stat);
return fl.nstat;
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:686,694 –
1999/0423/sys/src/9/alphapc/devfloppy.c:659,665
|
|
1999/0415
| |
return -1;
floppywait();
if(fl.nstat < 2){
mb();
DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
mb();
fl.confused = 1;
return -1;
}
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:729,741 –
1999/0423/sys/src/9/alphapc/devfloppy.c:700,708
|
|
1999/0415
| |
splhi();
fl.ncmd = 1;
fl.cmd[0] = 0;
mb();
outb(Pdor, 0);
mb();
delay(10);
mb();
outb(Pdor, Fintena|Fena);
mb();
delay(10);
spllo();
fl.motor = 0;
|
|
1999/0415/sys/src/9/alphapc/devfloppy.c:747,755 –
1999/0423/sys/src/9/alphapc/devfloppy.c:714,720
|
|
1999/0415
| |
dp->confused = 1;
/* set rate to a known value */
mb();
outb(Pdsr, 0);
mb();
fl.rate = 0;
DPRINT("floppyrevive out\n");
|
|
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:39,45 –
1999/0501/sys/src/9/alphapc/devfloppy.c:39,45
(short | long)
|
|
1999/0415
| |
};
#define DPRINT if(floppydebug)print
int floppydebug = 0;
|
|
1999/0501
| |
int floppydebug = 1;
|
|
1999/0415
| |
/*
* types of drive (from PC equipment byte)
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:56,61 –
1999/0501/sys/src/9/alphapc/devfloppy.c:56,62
|
|
1999/0415
| |
FType floppytype[] =
{
{ "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
|
|
1999/0501
| |
/*
|
|
1999/0415
| |
{ "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:62,67 –
1999/0501/sys/src/9/alphapc/devfloppy.c:63,69
|
|
1999/0415
| |
{ "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
{ "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
{ "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
|
|
1999/0501
| |
*/
|
|
1999/0415
| |
};
/*
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:533,538 –
1999/0501/sys/src/9/alphapc/devfloppy.c:535,541
|
|
1999/0415
| |
microdelay(8); /* for machine independence */
}
outb(Pfdata, fl.cmd[i]);
|
|
1999/0501
| |
microdelay(8); /* for machine independence */
|
|
1999/0415
| |
}
return 0;
}
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:636,642 –
1999/0501/sys/src/9/alphapc/devfloppy.c:639,649
|
|
1999/0415
| |
static void
floppywait(void)
{
|
|
1999/0501
| |
vlong t0, t1;
t0 = fastticks(nil);
|
|
1999/0415
| |
tsleep(&fl.r, cmddone, 0, 5000);
|
|
1999/0501
| |
t1 = fastticks(nil);
print("wait %lld ticks\n", t1-t0);
|
|
1999/0415
| |
if(!cmddone(0)){
floppyintr(0);
fl.confused = 1;
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:680,688 –
1999/0501/sys/src/9/alphapc/devfloppy.c:687,708
|
|
1999/0415
| |
return 0;
}
|
|
1999/0501
| |
static void
specify(void)
{
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fspec;
fl.cmd[fl.ncmd++] = 0;
fl.cmd[fl.ncmd++] = 1;
if(floppycmd() < 0)
return;
floppywait();
fldump();
}
|
|
1999/0415
| |
/*
* if the controller or a specific drive is in a confused state,
* reset it and get back to a kown state
|
|
1999/0501
| |
* reset it and get back to a known state
|
|
1999/0415
| |
*/
static void
floppyrevive(void)
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:774,780 –
1999/0501/sys/src/9/alphapc/devfloppy.c:794,800
|
|
1999/0415
| |
/* retry on error (until it gets ridiculous) */
tries = 0;
while(waserror()){
if(tries++ > 20)
|
|
1999/0501
| |
if(tries++ > 2/*0*/)
|
|
1999/0415
| |
nexterror();
DPRINT("floppyxfer: retrying\n");
/*floppyon(dp);*/
|
|
1999/0423/sys/src/9/alphapc/devfloppy.c:820,825 –
1999/0501/sys/src/9/alphapc/devfloppy.c:840,847
|
|
1999/0415
| |
/*
* give bus to DMA, floppyintr() will read result
*/
|
|
1999/0501
| |
delay(10);
print("msr 0x%2.2uX\n", inb(Pmsr));
|
|
1999/0415
| |
floppywait();
dmaend(DMAchan);
poperror();
|
|
|
|
1999/0501/sys/src/9/alphapc/devfloppy.c:842,847 –
1999/0504/sys/src/9/alphapc/devfloppy.c:842,848
(short | long)
|
|
1999/0415
| |
*/
|
|
1999/0501
| |
delay(10);
print("msr 0x%2.2uX\n", inb(Pmsr));
|
|
1999/0504
| |
xdmastatus(DMAchan);
|
|
1999/0415
| |
floppywait();
dmaend(DMAchan);
poperror();
|
|
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:39,45 –
1999/0506/sys/src/9/alphapc/devfloppy.c:39,45
(short | long)
|
|
1999/0415
| |
};
#define DPRINT if(floppydebug)print
|
|
1999/0501
| |
int floppydebug = 1;
|
|
1999/0506
| |
int floppydebug = 0;
|
|
1999/0415
| |
/*
* types of drive (from PC equipment byte)
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:106,112 –
1999/0506/sys/src/9/alphapc/devfloppy.c:106,113
|
|
1999/0415
| |
static long floppyxfer(FDrive*, int, void*, long, long);
Dirtab floppydir[]={
"fd0disk", {Qdata + 0}, 0, 0660,
|
|
1999/0506
| |
// "fd0disk", {Qdata + 0}, 0, 0660,
"fd0disk", {Qdata + 0}, 0, 0666,
|
|
1999/0415
| |
"fd0ctl", {Qctl + 0}, 0, 0660,
"fd1disk", {Qdata + 1}, 0, 0660,
"fd1ctl", {Qctl + 1}, 0, 0660,
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:535,541 –
1999/0506/sys/src/9/alphapc/devfloppy.c:536,541
|
|
1999/0415
| |
microdelay(8); /* for machine independence */
}
outb(Pfdata, fl.cmd[i]);
|
|
1999/0501
| |
microdelay(8); /* for machine independence */
|
|
1999/0415
| |
}
return 0;
}
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:639,649 –
1999/0506/sys/src/9/alphapc/devfloppy.c:639,645
|
|
1999/0415
| |
static void
floppywait(void)
{
|
|
1999/0501
| |
vlong t0, t1;
t0 = fastticks(nil);
|
|
1999/0415
| |
tsleep(&fl.r, cmddone, 0, 5000);
|
|
1999/0501
| |
t1 = fastticks(nil);
print("wait %lld ticks\n", t1-t0);
|
|
1999/0415
| |
if(!cmddone(0)){
floppyintr(0);
fl.confused = 1;
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:688,693 –
1999/0506/sys/src/9/alphapc/devfloppy.c:684,709
|
|
1999/0415
| |
}
|
|
1999/0501
| |
static void
|
|
1999/0506
| |
dumpreg(void)
{
int i;
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fdumpreg;
if(floppycmd() < 0)
return;
floppywait();
if(fl.nstat < 0){
print("dumpreg bad %d\n", fl.nstat);
fldump();
return;
}
for(i = 0; i < fl.nstat; i++)
print(" %2.2uX", fl.stat[i]);
print("\n");
}
static void
|
|
1999/0501
| |
specify(void)
{
fl.ncmd = 0;
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:794,800 –
1999/0506/sys/src/9/alphapc/devfloppy.c:810,816
|
|
1999/0415
| |
/* retry on error (until it gets ridiculous) */
tries = 0;
while(waserror()){
|
|
1999/0501
| |
if(tries++ > 2/*0*/)
|
|
1999/0506
| |
if(tries++ > 20)
|
|
1999/0415
| |
nexterror();
DPRINT("floppyxfer: retrying\n");
/*floppyon(dp);*/
|
|
1999/0504/sys/src/9/alphapc/devfloppy.c:840,848 –
1999/0506/sys/src/9/alphapc/devfloppy.c:856,861
|
|
1999/0415
| |
/*
* give bus to DMA, floppyintr() will read result
*/
|
|
1999/0501
| |
delay(10);
print("msr 0x%2.2uX\n", inb(Pmsr));
|
|
1999/0504
| |
xdmastatus(DMAchan);
|
|
1999/0415
| |
floppywait();
dmaend(DMAchan);
poperror();
|
|
|
|
1999/0506/sys/src/9/alphapc/devfloppy.c:56,62 –
1999/0507/sys/src/9/alphapc/devfloppy.c:56,61
(short | long)
|
|
1999/0415
| |
FType floppytype[] =
{
{ "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
|
|
1999/0501
| |
/*
|
|
1999/0415
| |
{ "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
|
|
1999/0506/sys/src/9/alphapc/devfloppy.c:63,69 –
1999/0507/sys/src/9/alphapc/devfloppy.c:62,67
|
|
1999/0415
| |
{ "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
{ "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
{ "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
|
|
1999/0501
| |
*/
|
|
1999/0415
| |
};
/*
|
|
1999/0506/sys/src/9/alphapc/devfloppy.c:806,811 –
1999/0507/sys/src/9/alphapc/devfloppy.c:804,811
|
|
1999/0415
| |
return 0;
if(off + n > dp->t->cap)
n = dp->t->cap - off;
|
|
1999/0507
| |
if(cmd == Fread)
memset(a, 0x55, n);
|
|
1999/0415
| |
/* retry on error (until it gets ridiculous) */
tries = 0;
|
|
|
|
1999/0507/sys/src/9/alphapc/devfloppy.c:911,917 –
2000/0308/sys/src/9/alphapc/devfloppy.c:911,917
(short | long)
|
|
1999/0415
| |
/*
* set the type
*/
if(parsefields(params, f, 3, " ") > 1){
|
|
2000/0308
| |
if(getfields(params, f, 3, 1, " ") > 1){
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
dp->t = t;
|
|
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:104,110 –
2001/0727/sys/src/9/alphapc/devfloppy.c:104,110
(short | long)
|
|
1999/0415
| |
static long floppyxfer(FDrive*, int, void*, long, long);
Dirtab floppydir[]={
|
|
1999/0506
| |
// "fd0disk", {Qdata + 0}, 0, 0660,
|
|
2001/0727
| |
".", {Qdir, 0, QTDIR}, 0, 0550,
|
|
1999/0506
| |
"fd0disk", {Qdata + 0}, 0, 0666,
|
|
1999/0415
| |
"fd0ctl", {Qctl + 0}, 0, 0660,
"fd1disk", {Qdata + 1}, 0, 0660,
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:134,140 –
2001/0727/sys/src/9/alphapc/devfloppy.c:134,140
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
if(dp->dt == t->dt){
dp->t = t;
floppydir[NFDIR*dp->dev].length = dp->t->cap;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
break;
}
}
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:212,233 –
2001/0727/sys/src/9/alphapc/devfloppy.c:212,233
|
|
1999/0415
| |
return devattach('f', spec);
}
static int
floppywalk(Chan *c, char *name)
|
|
2001/0727
| |
static Walkqid*
floppywalk(Chan *c, Chan *nc, char **name, int nname)
|
|
1999/0415
| |
{
return devwalk(c, name, floppydir, fl.ndrive*NFDIR, devgen);
|
|
2001/0727
| |
return devwalk(c, nc, name, nname, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
static void
floppystat(Chan *c, char *dp)
|
|
2001/0727
| |
static int
floppystat(Chan *c, uchar *dp, int n)
|
|
1999/0415
| |
{
devstat(c, dp, floppydir, fl.ndrive*NFDIR, devgen);
|
|
2001/0727
| |
return devstat(c, dp, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
static Chan*
floppyopen(Chan *c, int omode)
{
return devopen(c, omode, floppydir, fl.ndrive*NFDIR, devgen);
|
|
2001/0727
| |
return devopen(c, omode, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
static void
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:280,286 –
2001/0727/sys/src/9/alphapc/devfloppy.c:280,286
|
|
1999/0415
| |
if(dp->dt == dp->t->dt)
break;
}
floppydir[NFDIR*dp->dev].length = dp->t->cap;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
floppyon(dp);
DPRINT("changed: trying %s\n", dp->t->name);
fldump();
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:328,335 –
2001/0727/sys/src/9/alphapc/devfloppy.c:328,335
|
|
1999/0415
| |
uchar *aa;
ulong offset = off;
if(c->qid.path == CHDIR)
return devdirread(c, a, n, floppydir, fl.ndrive*NFDIR, devgen);
|
|
2001/0727
| |
if(c->qid.type & QTDIR)
return devdirread(c, a, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
rv = 0;
dp = &fl.d[c->qid.path & ~Qmask];
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:915,921 –
2001/0727/sys/src/9/alphapc/devfloppy.c:915,921
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
dp->t = t;
floppydir[NFDIR*dp->dev].length = dp->t->cap;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
break;
}
}
|
|
2000/0308/sys/src/9/alphapc/devfloppy.c:1043,1049 –
2001/0727/sys/src/9/alphapc/devfloppy.c:1043,1048
|
|
1999/0415
| |
floppyreset,
devinit,
floppyattach,
devclone,
floppywalk,
floppystat,
floppyopen,
|
|
|
|
2001/0727/sys/src/9/alphapc/devfloppy.c:911,917 –
2001/1117/sys/src/9/alphapc/devfloppy.c:911,917
(short | long)
|
|
1999/0415
| |
/*
* set the type
*/
|
|
2000/0308
| |
if(getfields(params, f, 3, 1, " ") > 1){
|
|
2001/1117
| |
if(tokenize(params, f, 3) > 1){
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
dp->t = t;
|
|
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:92,98 –
2001/1122/sys/src/9/alphapc/devfloppy.c:92,98
(short | long)
|
|
1999/0415
| |
* predeclared
*/
static int cmddone(void*);
static void floppyformat(FDrive*, char*);
|
|
2001/1122
| |
static void floppyformat(FDrive*, Cmdbuf*);
|
|
1999/0415
| |
static void floppykproc(void*);
static void floppypos(FDrive*,long);
static int floppyrecal(FDrive*);
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:100,111 –
2001/1122/sys/src/9/alphapc/devfloppy.c:100,111
|
|
1999/0415
| |
static void floppyrevive(void);
static long floppyseek(FDrive*, long);
static int floppysense(void);
static void floppywait(void);
|
|
2001/1122
| |
static void floppywait(int);
|
|
1999/0415
| |
static long floppyxfer(FDrive*, int, void*, long, long);
Dirtab floppydir[]={
|
|
2001/0727
| |
".", {Qdir, 0, QTDIR}, 0, 0550,
|
|
1999/0506
| |
"fd0disk", {Qdata + 0}, 0, 0666,
|
|
2001/1122
| |
"fd0disk", {Qdata + 0}, 0, 0660,
|
|
1999/0415
| |
"fd0ctl", {Qctl + 0}, 0, 0660,
"fd1disk", {Qdata + 1}, 0, 0660,
"fd1ctl", {Qctl + 1}, 0, 0660,
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:116,121 –
2001/1122/sys/src/9/alphapc/devfloppy.c:116,137
|
|
1999/0415
| |
};
#define NFDIR 2 /* directory entries/drive */
|
|
2001/1122
| |
enum
{
CMdebug,
CMeject,
CMformat,
CMreset,
};
static Cmdtab floppyctlmsg[] =
{
CMdebug, "debug", 1,
CMeject, "eject", 1,
CMformat, "format", 0,
CMreset, "reset", 1,
};
|
|
1999/0415
| |
static void
fldump(void)
{
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:147,152 –
2001/1122/sys/src/9/alphapc/devfloppy.c:163,170
|
|
1999/0415
| |
ulong maxtsize;
floppysetup0(&fl);
|
|
2001/1122
| |
if(fl.ndrive == 0)
return;
|
|
1999/0415
| |
/*
* init dependent parameters
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:202,207 –
2001/1122/sys/src/9/alphapc/devfloppy.c:220,228
|
|
1999/0415
| |
{
static int kstarted;
|
|
2001/1122
| |
if(fl.ndrive == 0)
error(Enodev);
|
|
1999/0415
| |
if(kstarted == 0){
/*
* watchdog to turn off the motors
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:268,279 –
2001/1122/sys/src/9/alphapc/devfloppy.c:289,312
|
|
1999/0415
| |
DPRINT("changed\n");
fldump();
dp->vers++;
floppysetdef(dp);
start = dp->t;
|
|
2001/1122
| |
dp->maxtries = 3; /* limit it when we're probing */
/* floppyon will fail if there's a controller but no drive */
|
|
1999/0415
| |
dp->confused = 1; /* make floppyon recal */
floppyon(dp);
|
|
2001/1122
| |
if(floppyon(dp) < 0)
error(Eio);
/* seek to the first track */
|
|
1999/0415
| |
floppyseek(dp, dp->t->heads*dp->t->tsize);
while(waserror()){
|
|
2001/1122
| |
/*
* if first attempt doesn't reset changed bit, there's
* no floppy there
*/
if(inb(Pdir)&Fchange)
nexterror();
|
|
1999/0415
| |
while(++dp->t){
if(dp->t == &floppytype[nelem(floppytype)])
dp->t = floppytype;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:281,294 –
2001/1122/sys/src/9/alphapc/devfloppy.c:314,334
|
|
1999/0415
| |
break;
}
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
floppyon(dp);
|
|
2001/1122
| |
/* floppyon will fail if there's a controller but no drive */
if(floppyon(dp) < 0)
error(Eio);
|
|
1999/0415
| |
DPRINT("changed: trying %s\n", dp->t->name);
fldump();
if(dp->t == start)
nexterror();
}
|
|
2001/1122
| |
/* if the read succeeds, we've got the density right */
|
|
1999/0415
| |
floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
poperror();
|
|
2001/1122
| |
dp->maxtries = 20;
|
|
1999/0415
| |
}
old = c->qid.vers;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:372,378 –
2001/1122/sys/src/9/alphapc/devfloppy.c:412,417
|
|
1999/0415
| |
return rv;
}
#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
static long
floppywrite(Chan *c, void *a, long n, vlong off)
{
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:379,385 –
2001/1122/sys/src/9/alphapc/devfloppy.c:418,425
|
|
1999/0415
| |
FDrive *dp;
long rv, i;
char *aa = a;
char ctlmsg[64];
|
|
2001/1122
| |
Cmdbuf *cb;
Cmdtab *ct;
|
|
1999/0415
| |
ulong offset = off;
rv = 0;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:409,436 –
2001/1122/sys/src/9/alphapc/devfloppy.c:449,484
|
|
1999/0415
| |
break;
case Qctl:
rv = n;
|
|
2001/1122
| |
cb = parsecmd(a, n);
if(waserror()){
free(cb);
nexterror();
}
|
|
1999/0415
| |
qlock(&fl);
if(waserror()){
qunlock(&fl);
nexterror();
}
if(n >= sizeof(ctlmsg))
n = sizeof(ctlmsg) - 1;
memmove(ctlmsg, aa, n);
ctlmsg[n] = 0;
if(SNCMP(ctlmsg, "eject") == 0){
|
|
2001/1122
| |
ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg));
switch(ct->index){
case CMeject:
|
|
1999/0415
| |
floppyeject(dp);
} else if(SNCMP(ctlmsg, "reset") == 0){
|
|
2001/1122
| |
break;
case CMformat:
floppyformat(dp, cb);
break;
case CMreset:
|
|
1999/0415
| |
fl.confused = 1;
floppyon(dp);
} else if(SNCMP(ctlmsg, "format") == 0){
floppyformat(dp, ctlmsg);
} else if(SNCMP(ctlmsg, "debug") == 0){
|
|
2001/1122
| |
break;
case CMdebug:
|
|
1999/0415
| |
floppydebug = 1;
} else
error(Ebadctl);
|
|
2001/1122
| |
break;
}
|
|
1999/0415
| |
poperror();
qunlock(&fl);
|
|
2001/1122
| |
poperror();
free(cb);
|
|
1999/0415
| |
break;
default:
panic("floppywrite: bad qid");
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:463,469 –
2001/1122/sys/src/9/alphapc/devfloppy.c:511,517
|
|
1999/0415
| |
/*
* start a floppy drive's motor.
*/
static void
|
|
2001/1122
| |
static int
|
|
1999/0415
| |
floppyon(FDrive *dp)
{
int alreadyon;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:497,502 –
2001/1122/sys/src/9/alphapc/devfloppy.c:545,555
|
|
1999/0415
| |
break;
dp->lasttouched = m->ticks;
fl.selected = dp;
|
|
2001/1122
| |
/* return -1 if this didn't work */
if(dp->confused)
return -1;
return 0;
|
|
1999/0415
| |
}
/*
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:635,643 –
2001/1122/sys/src/9/alphapc/devfloppy.c:688,696
|
|
1999/0415
| |
* routine to try to clear any conditions.
*/
static void
floppywait(void)
|
|
2001/1122
| |
floppywait(int slow)
|
|
1999/0415
| |
{
tsleep(&fl.r, cmddone, 0, 5000);
|
|
2001/1122
| |
tsleep(&fl.r, cmddone, 0, slow ? 5000 : 1000);
|
|
1999/0415
| |
if(!cmddone(0)){
floppyintr(0);
fl.confused = 1;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:658,664 –
2001/1122/sys/src/9/alphapc/devfloppy.c:711,717
|
|
1999/0415
| |
fl.cmd[fl.ncmd++] = dp->dev;
if(floppycmd() < 0)
return -1;
floppywait();
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
if(fl.nstat < 2){
DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
fl.confused = 1;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:681,719 –
2001/1122/sys/src/9/alphapc/devfloppy.c:734,739
|
|
1999/0415
| |
return 0;
}
|
|
1999/0501
| |
static void
|
|
1999/0506
| |
dumpreg(void)
{
int i;
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fdumpreg;
if(floppycmd() < 0)
return;
floppywait();
if(fl.nstat < 0){
print("dumpreg bad %d\n", fl.nstat);
fldump();
return;
}
for(i = 0; i < fl.nstat; i++)
print(" %2.2uX", fl.stat[i]);
print("\n");
}
static void
|
|
1999/0501
| |
specify(void)
{
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fspec;
fl.cmd[fl.ncmd++] = 0;
fl.cmd[fl.ncmd++] = 1;
if(floppycmd() < 0)
return;
floppywait();
fldump();
}
|
|
1999/0415
| |
/*
* if the controller or a specific drive is in a confused state,
|
|
1999/0501
| |
* reset it and get back to a known state
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:741,747 –
2001/1122/sys/src/9/alphapc/devfloppy.c:761,767
|
|
1999/0415
| |
spllo();
fl.motor = 0;
fl.confused = 0;
floppywait();
|
|
2001/1122
| |
floppywait(0);
|
|
1999/0415
| |
/* mark all drives in an unknown state */
for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:775,781 –
2001/1122/sys/src/9/alphapc/devfloppy.c:795,801
|
|
1999/0415
| |
fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
if(floppycmd() < 0)
return -1;
floppywait();
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
if(fl.nstat < 2){
DPRINT("seek: confused\n");
fl.confused = 1;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:804,819 –
2001/1122/sys/src/9/alphapc/devfloppy.c:824,836
|
|
1999/0415
| |
return 0;
if(off + n > dp->t->cap)
n = dp->t->cap - off;
|
|
1999/0507
| |
if(cmd == Fread)
memset(a, 0x55, n);
|
|
1999/0415
| |
/* retry on error (until it gets ridiculous) */
tries = 0;
while(waserror()){
|
|
1999/0506
| |
if(tries++ > 20)
|
|
2001/1122
| |
if(tries++ >= dp->maxtries)
|
|
1999/0415
| |
nexterror();
DPRINT("floppyxfer: retrying\n");
/*floppyon(dp);*/
}
dp->len = n;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:856,862 –
2001/1122/sys/src/9/alphapc/devfloppy.c:873,879
|
|
1999/0415
| |
/*
* give bus to DMA, floppyintr() will read result
*/
floppywait();
|
|
2001/1122
| |
floppywait(0);
|
|
1999/0415
| |
dmaend(DMAchan);
poperror();
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:900,919 –
2001/1122/sys/src/9/alphapc/devfloppy.c:917,935
|
|
1999/0415
| |
* format a track
*/
static void
floppyformat(FDrive *dp, char *params)
|
|
2001/1122
| |
floppyformat(FDrive *dp, Cmdbuf *cb)
|
|
1999/0415
| |
{
int cyl, h, sec;
ulong track;
uchar *buf, *bp;
FType *t;
char *f[3];
/*
* set the type
*/
|
|
2001/1117
| |
if(tokenize(params, f, 3) > 1){
|
|
2001/1122
| |
if(cb->nf == 2){
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
|
|
2001/1122
| |
if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){
|
|
1999/0415
| |
dp->t = t;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
break;
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:921,929 –
2001/1122/sys/src/9/alphapc/devfloppy.c:937,948
|
|
1999/0415
| |
}
if(t >= &floppytype[nelem(floppytype)])
error(Ebadarg);
} else {
|
|
2001/1122
| |
} else if(cb->nf == 1){
|
|
1999/0415
| |
floppysetdef(dp);
t = dp->t;
|
|
2001/1122
| |
} else {
cmderror(cb, "invalid floppy format command");
SET(t);
|
|
1999/0415
| |
}
/*
|
|
2001/1117/sys/src/9/alphapc/devfloppy.c:992,998 –
2001/1122/sys/src/9/alphapc/devfloppy.c:1011,1017
|
|
1999/0415
| |
/*
* give bus to DMA, floppyintr() will read result
*/
floppywait();
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
dmaend(DMAchan);
poperror();
|
|
|
|
2001/1122/sys/src/9/alphapc/devfloppy.c:1,1076 –
2001/1211/sys/src/9/alphapc/devfloppy.c:1
(short | long)
|
|
1999/0415
| |
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "floppy.h"
/* Intel 82077A (8272A compatible) floppy controller */
/* This module expects the following functions to be defined
* elsewhere:
*
* inb()
* outb()
* floppyexec()
* floppyeject()
* floppysetup0()
* floppysetup1()
* dmainit()
* dmasetup()
* dmaend()
*
* On DMA systems, floppyexec() should be an empty function;
* on non-DMA systems, dmaend() should be an empty function;
* dmasetup() may enforce maximum transfer sizes.
*/
enum {
/* file types */
Qdir= 0,
Qdata= (1<<2),
Qctl= (2<<2),
Qmask= (3<<2),
DMAchan= 2, /* floppy dma channel */
};
#define DPRINT if(floppydebug)print
|
|
1999/0506
| |
int floppydebug = 0;
|
|
1999/0415
| |
/*
* types of drive (from PC equipment byte)
*/
enum
{
Tnone= 0,
T360kb= 1,
T1200kb= 2,
T720kb= 3,
T1440kb= 4,
};
FType floppytype[] =
{
{ "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
{ "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
{ "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
{ "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
{ "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
{ "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
};
/*
* bytes per sector encoding for the controller.
* - index for b2c is is (bytes per sector/128).
* - index for c2b is code from b2c
*/
static int b2c[] =
{
[1] 0,
[2] 1,
[4] 2,
[8] 3,
};
static int c2b[] =
{
128,
256,
512,
1024,
};
FController fl;
#define MOTORBIT(i) (1<<((i)+4))
/*
* predeclared
*/
static int cmddone(void*);
|
|
2001/1122
| |
static void floppyformat(FDrive*, Cmdbuf*);
|
|
1999/0415
| |
static void floppykproc(void*);
static void floppypos(FDrive*,long);
static int floppyrecal(FDrive*);
static int floppyresult(void);
static void floppyrevive(void);
static long floppyseek(FDrive*, long);
static int floppysense(void);
|
|
2001/1122
| |
static void floppywait(int);
|
|
1999/0415
| |
static long floppyxfer(FDrive*, int, void*, long, long);
Dirtab floppydir[]={
|
|
2001/0727
| |
".", {Qdir, 0, QTDIR}, 0, 0550,
|
|
2001/1122
| |
"fd0disk", {Qdata + 0}, 0, 0660,
|
|
1999/0415
| |
"fd0ctl", {Qctl + 0}, 0, 0660,
"fd1disk", {Qdata + 1}, 0, 0660,
"fd1ctl", {Qctl + 1}, 0, 0660,
"fd2disk", {Qdata + 2}, 0, 0660,
"fd2ctl", {Qctl + 2}, 0, 0660,
"fd3disk", {Qdata + 3}, 0, 0660,
"fd3ctl", {Qctl + 3}, 0, 0660,
};
#define NFDIR 2 /* directory entries/drive */
|
|
2001/1122
| |
enum
{
CMdebug,
CMeject,
CMformat,
CMreset,
};
static Cmdtab floppyctlmsg[] =
{
CMdebug, "debug", 1,
CMeject, "eject", 1,
CMformat, "format", 0,
CMreset, "reset", 1,
};
|
|
1999/0415
| |
static void
fldump(void)
{
DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
inb(Pdor), inb(Pmsr), inb(Pdir));
}
/*
* set floppy drive to its default type
*/
static void
floppysetdef(FDrive *dp)
{
FType *t;
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
if(dp->dt == t->dt){
dp->t = t;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
break;
}
}
static void
floppyreset(void)
{
FDrive *dp;
FType *t;
ulong maxtsize;
floppysetup0(&fl);
|
|
2001/1122
| |
if(fl.ndrive == 0)
return;
|
|
1999/0415
| |
/*
* init dependent parameters
*/
maxtsize = 0;
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
t->cap = t->bytes * t->heads * t->sectors * t->tracks;
t->bcode = b2c[t->bytes/128];
t->tsize = t->bytes * t->sectors;
if(maxtsize < t->tsize)
maxtsize = t->tsize;
}
|
|
1999/0423
| |
dmainit(DMAchan, maxtsize);
|
|
1999/0415
| |
/*
* allocate the drive storage
*/
fl.d = xalloc(fl.ndrive*sizeof(FDrive));
fl.selected = fl.d;
/*
* stop the motors
*/
fl.motor = 0;
delay(10);
outb(Pdor, fl.motor | Fintena | Fena);
delay(10);
/*
* init drives
*/
for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
dp->dev = dp - fl.d;
dp->dt = T1440kb;
floppysetdef(dp);
dp->cyl = -1; /* because we don't know */
dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
dp->ccyl = -1;
dp->vers = 0;
}
/*
* first operation will recalibrate
*/
fl.confused = 1;
floppysetup1(&fl);
}
static Chan*
floppyattach(char *spec)
{
static int kstarted;
|
|
2001/1122
| |
if(fl.ndrive == 0)
error(Enodev);
|
|
1999/0415
| |
if(kstarted == 0){
/*
* watchdog to turn off the motors
*/
kstarted = 1;
kproc("floppy", floppykproc, 0);
}
return devattach('f', spec);
}
|
|
2001/0727
| |
static Walkqid*
floppywalk(Chan *c, Chan *nc, char **name, int nname)
|
|
1999/0415
| |
{
|
|
2001/0727
| |
return devwalk(c, nc, name, nname, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
|
|
2001/0727
| |
static int
floppystat(Chan *c, uchar *dp, int n)
|
|
1999/0415
| |
{
|
|
2001/0727
| |
return devstat(c, dp, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
static Chan*
floppyopen(Chan *c, int omode)
{
|
|
2001/0727
| |
return devopen(c, omode, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
}
static void
floppyclose(Chan *)
{
}
static void
islegal(ulong offset, long n, FDrive *dp)
{
if(offset % dp->t->bytes)
error(Ebadarg);
if(n % dp->t->bytes)
error(Ebadarg);
}
/*
* check if the floppy has been replaced under foot. cause
* an error if it has.
*
* a seek and a read clears the condition. this was determined
* experimentally, there has to be a better way.
*
* if the read fails, cycle through the possible floppy
* density till one works or we've cycled through all
* possibilities for this drive.
*/
static void
changed(Chan *c, FDrive *dp)
{
ulong old;
FType *start;
/*
* if floppy has changed or first time through
*/
if((inb(Pdir)&Fchange) || dp->vers == 0){
DPRINT("changed\n");
fldump();
dp->vers++;
start = dp->t;
|
|
2001/1122
| |
dp->maxtries = 3; /* limit it when we're probing */
/* floppyon will fail if there's a controller but no drive */
|
|
1999/0415
| |
dp->confused = 1; /* make floppyon recal */
|
|
2001/1122
| |
if(floppyon(dp) < 0)
error(Eio);
/* seek to the first track */
|
|
1999/0415
| |
floppyseek(dp, dp->t->heads*dp->t->tsize);
while(waserror()){
|
|
2001/1122
| |
/*
* if first attempt doesn't reset changed bit, there's
* no floppy there
*/
if(inb(Pdir)&Fchange)
nexterror();
|
|
1999/0415
| |
while(++dp->t){
if(dp->t == &floppytype[nelem(floppytype)])
dp->t = floppytype;
if(dp->dt == dp->t->dt)
break;
}
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
2001/1122
| |
/* floppyon will fail if there's a controller but no drive */
if(floppyon(dp) < 0)
error(Eio);
|
|
1999/0415
| |
DPRINT("changed: trying %s\n", dp->t->name);
fldump();
if(dp->t == start)
nexterror();
}
|
|
2001/1122
| |
/* if the read succeeds, we've got the density right */
|
|
1999/0415
| |
floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
poperror();
|
|
2001/1122
| |
dp->maxtries = 20;
|
|
1999/0415
| |
}
old = c->qid.vers;
c->qid.vers = dp->vers;
if(old && old != dp->vers)
error(Eio);
}
static int
readtrack(FDrive *dp, int cyl, int head)
{
int i, nn, sofar;
ulong pos;
nn = dp->t->tsize;
if(dp->ccyl==cyl && dp->chead==head)
return nn;
pos = (cyl*dp->t->heads+head) * nn;
for(sofar = 0; sofar < nn; sofar += i){
dp->ccyl = -1;
i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
if(i <= 0)
return -1;
}
dp->ccyl = cyl;
dp->chead = head;
return nn;
}
static long
floppyread(Chan *c, void *a, long n, vlong off)
{
FDrive *dp;
long rv;
int sec, head, cyl;
long len;
uchar *aa;
ulong offset = off;
|
|
2001/0727
| |
if(c->qid.type & QTDIR)
return devdirread(c, a, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
|
|
1999/0415
| |
rv = 0;
dp = &fl.d[c->qid.path & ~Qmask];
switch ((int)(c->qid.path & Qmask)) {
case Qdata:
islegal(offset, n, dp);
aa = a;
qlock(&fl);
if(waserror()){
qunlock(&fl);
nexterror();
}
floppyon(dp);
changed(c, dp);
for(rv = 0; rv < n; rv += len){
/*
* all xfers come out of the track cache
*/
dp->len = n - rv;
floppypos(dp, offset+rv);
cyl = dp->tcyl;
head = dp->thead;
len = dp->len;
sec = dp->tsec;
if(readtrack(dp, cyl, head) < 0)
break;
memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
}
qunlock(&fl);
poperror();
break;
case Qctl:
return readstr(offset, a, n, dp->t->name);
default:
panic("floppyread: bad qid");
}
return rv;
}
static long
floppywrite(Chan *c, void *a, long n, vlong off)
{
FDrive *dp;
long rv, i;
char *aa = a;
|
|
2001/1122
| |
Cmdbuf *cb;
Cmdtab *ct;
|
|
1999/0415
| |
ulong offset = off;
rv = 0;
dp = &fl.d[c->qid.path & ~Qmask];
switch ((int)(c->qid.path & Qmask)) {
case Qdata:
islegal(offset, n, dp);
qlock(&fl);
if(waserror()){
qunlock(&fl);
nexterror();
}
floppyon(dp);
changed(c, dp);
for(rv = 0; rv < n; rv += i){
floppypos(dp, offset+rv);
if(dp->tcyl == dp->ccyl)
dp->ccyl = -1;
i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
if(i < 0)
break;
if(i == 0)
error(Eio);
}
qunlock(&fl);
poperror();
break;
case Qctl:
rv = n;
|
|
2001/1122
| |
cb = parsecmd(a, n);
if(waserror()){
free(cb);
nexterror();
}
|
|
1999/0415
| |
qlock(&fl);
if(waserror()){
qunlock(&fl);
nexterror();
}
|
|
2001/1122
| |
ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg));
switch(ct->index){
case CMeject:
|
|
1999/0415
| |
floppyeject(dp);
|
|
2001/1122
| |
break;
case CMformat:
floppyformat(dp, cb);
break;
case CMreset:
|
|
1999/0415
| |
fl.confused = 1;
floppyon(dp);
|
|
2001/1122
| |
break;
case CMdebug:
|
|
1999/0415
| |
floppydebug = 1;
|
|
2001/1122
| |
break;
}
|
|
1999/0415
| |
poperror();
qunlock(&fl);
|
|
2001/1122
| |
poperror();
free(cb);
|
|
1999/0415
| |
break;
default:
panic("floppywrite: bad qid");
}
return rv;
}
static void
floppykproc(void *)
{
FDrive *dp;
while(waserror())
;
for(;;){
for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
if((fl.motor&MOTORBIT(dp->dev))
&& TK2SEC(m->ticks - dp->lasttouched) > 5
&& canqlock(&fl)){
if(TK2SEC(m->ticks - dp->lasttouched) > 5)
floppyoff(dp);
qunlock(&fl);
}
}
tsleep(&fl.kr, return0, 0, 1000);
}
}
/*
* start a floppy drive's motor.
*/
|
|
2001/1122
| |
static int
|
|
1999/0415
| |
floppyon(FDrive *dp)
{
int alreadyon;
int tries;
if(fl.confused)
floppyrevive();
/* start motor and select drive */
alreadyon = fl.motor & MOTORBIT(dp->dev);
fl.motor |= MOTORBIT(dp->dev);
outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
if(!alreadyon){
/* wait for drive to spin up */
tsleep(&dp->r, return0, 0, 750);
/* clear any pending interrupts */
floppysense();
}
/* set transfer rate */
if(fl.rate != dp->t->rate){
fl.rate = dp->t->rate;
outb(Pdsr, fl.rate);
}
/* get drive to a known cylinder */
if(dp->confused)
for(tries = 0; tries < 4; tries++)
if(floppyrecal(dp) >= 0)
break;
dp->lasttouched = m->ticks;
fl.selected = dp;
|
|
2001/1122
| |
/* return -1 if this didn't work */
if(dp->confused)
return -1;
return 0;
|
|
1999/0415
| |
}
/*
* stop the floppy if it hasn't been used in 5 seconds
*/
static void
floppyoff(FDrive *dp)
{
fl.motor &= ~MOTORBIT(dp->dev);
outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
}
/*
* send a command to the floppy
*/
static int
floppycmd(void)
{
int i;
int tries;
fl.nstat = 0;
for(i = 0; i < fl.ncmd; i++){
for(tries = 0; ; tries++){
if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
break;
if(tries > 1000){
DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
fldump();
/* empty fifo, might have been a bad command */
floppyresult();
return -1;
}
microdelay(8); /* for machine independence */
}
outb(Pfdata, fl.cmd[i]);
}
return 0;
}
/*
* get a command result from the floppy
*
* when the controller goes ready waiting for a command
* (instead of sending results), we're done
*
*/
static int
floppyresult(void)
{
int i, s;
int tries;
/* get the result of the operation */
for(i = 0; i < sizeof(fl.stat); i++){
/* wait for status byte */
for(tries = 0; ; tries++){
s = inb(Pmsr)&(Ffrom|Fready);
if(s == Fready){
fl.nstat = i;
return fl.nstat;
}
if(s == (Ffrom|Fready))
break;
if(tries > 1000){
DPRINT("floppyresult: %d stats\n", i);
fldump();
fl.confused = 1;
return -1;
}
microdelay(8); /* for machine independence */
}
fl.stat[i] = inb(Pfdata);
}
fl.nstat = sizeof(fl.stat);
return fl.nstat;
}
/*
* calculate physical address of a logical byte offset into the disk
*
* truncate dp->length if it crosses a track boundary
*/
static void
floppypos(FDrive *dp, long off)
{
int lsec;
int ltrack;
int end;
lsec = off/dp->t->bytes;
ltrack = lsec/dp->t->sectors;
dp->tcyl = ltrack/dp->t->heads;
dp->tsec = (lsec % dp->t->sectors) + 1;
dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
/*
* can't read across track boundaries.
* if so, decrement the bytes to be read.
*/
end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
if(off+dp->len > end)
dp->len = end - off;
}
/*
* get the interrupt cause from the floppy.
*/
static int
floppysense(void)
{
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fsense;
if(floppycmd() < 0)
return -1;
if(floppyresult() < 2){
DPRINT("can't read sense response\n");
fldump();
fl.confused = 1;
return -1;
}
return 0;
}
static int
cmddone(void *)
{
return fl.ncmd == 0;
}
/*
* Wait for a floppy interrupt. If none occurs in 5 seconds, we
* may have missed one. This only happens on some portables which
* do power management behind our backs. Call the interrupt
* routine to try to clear any conditions.
*/
static void
|
|
2001/1122
| |
floppywait(int slow)
|
|
1999/0415
| |
{
|
|
2001/1122
| |
tsleep(&fl.r, cmddone, 0, slow ? 5000 : 1000);
|
|
1999/0415
| |
if(!cmddone(0)){
floppyintr(0);
fl.confused = 1;
}
}
/*
* we've lost the floppy position, go to cylinder 0.
*/
static int
floppyrecal(FDrive *dp)
{
dp->ccyl = -1;
dp->cyl = -1;
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Frecal;
fl.cmd[fl.ncmd++] = dp->dev;
if(floppycmd() < 0)
return -1;
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
if(fl.nstat < 2){
DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
fl.confused = 1;
return -1;
}
if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
DPRINT("recalibrate: failed\n");
dp->confused = 1;
return -1;
}
dp->cyl = fl.stat[1];
if(dp->cyl != 0){
DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
dp->cyl = -1;
dp->confused = 1;
return -1;
}
dp->confused = 0;
return 0;
}
/*
* if the controller or a specific drive is in a confused state,
|
|
1999/0501
| |
* reset it and get back to a known state
|
|
1999/0415
| |
*/
static void
floppyrevive(void)
{
FDrive *dp;
/*
* reset the controller if it's confused
*/
if(fl.confused){
DPRINT("floppyrevive in\n");
fldump();
/* reset controller and turn all motors off */
splhi();
fl.ncmd = 1;
fl.cmd[0] = 0;
outb(Pdor, 0);
delay(10);
outb(Pdor, Fintena|Fena);
delay(10);
spllo();
fl.motor = 0;
fl.confused = 0;
|
|
2001/1122
| |
floppywait(0);
|
|
1999/0415
| |
/* mark all drives in an unknown state */
for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
dp->confused = 1;
/* set rate to a known value */
outb(Pdsr, 0);
fl.rate = 0;
DPRINT("floppyrevive out\n");
fldump();
}
}
/*
* seek to the target cylinder
*
* interrupt, no results
*/
static long
floppyseek(FDrive *dp, long off)
{
floppypos(dp, off);
if(dp->cyl == dp->tcyl)
return dp->tcyl;
dp->cyl = -1;
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fseek;
fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
if(floppycmd() < 0)
return -1;
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
if(fl.nstat < 2){
DPRINT("seek: confused\n");
fl.confused = 1;
return -1;
}
if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
DPRINT("seek: failed\n");
dp->confused = 1;
return -1;
}
dp->cyl = dp->tcyl;
return dp->tcyl;
}
/*
* read or write to floppy. try up to three times.
*/
static long
floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
{
long offset;
int tries;
if(off >= dp->t->cap)
return 0;
if(off + n > dp->t->cap)
n = dp->t->cap - off;
/* retry on error (until it gets ridiculous) */
tries = 0;
while(waserror()){
|
|
2001/1122
| |
if(tries++ >= dp->maxtries)
|
|
1999/0415
| |
nexterror();
DPRINT("floppyxfer: retrying\n");
}
dp->len = n;
if(floppyseek(dp, off) < 0){
DPRINT("xfer: seek failed\n");
dp->confused = 1;
error(Eio);
}
/*
* set up the dma (dp->len may be trimmed)
*/
if(waserror()){
dmaend(DMAchan);
nexterror();
}
dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
if(dp->len < 0)
error(Eio);
/*
* start operation
*/
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
fl.cmd[fl.ncmd++] = dp->tcyl;
fl.cmd[fl.ncmd++] = dp->thead;
fl.cmd[fl.ncmd++] = dp->tsec;
fl.cmd[fl.ncmd++] = dp->t->bcode;
fl.cmd[fl.ncmd++] = dp->t->sectors;
fl.cmd[fl.ncmd++] = dp->t->gpl;
fl.cmd[fl.ncmd++] = 0xFF;
if(floppycmd() < 0)
error(Eio);
/* Poll ready bits and transfer data */
floppyexec((char*)a, dp->len, cmd==Fread);
/*
* give bus to DMA, floppyintr() will read result
*/
|
|
2001/1122
| |
floppywait(0);
|
|
1999/0415
| |
dmaend(DMAchan);
poperror();
/*
* check for errors
*/
if(fl.nstat < 7){
DPRINT("xfer: confused\n");
fl.confused = 1;
error(Eio);
}
if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
fl.stat[1], fl.stat[2]);
DPRINT("offset %lud len %ld\n", off, dp->len);
if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
DPRINT("DMA overrun: retry\n");
} else
dp->confused = 1;
error(Eio);
}
/*
* check for correct cylinder
*/
offset = fl.stat[3] * dp->t->heads + fl.stat[4];
offset = offset*dp->t->sectors + fl.stat[5] - 1;
offset = offset * c2b[fl.stat[6]];
if(offset != off+dp->len){
DPRINT("xfer: ends on wrong cyl\n");
dp->confused = 1;
error(Eio);
}
poperror();
dp->lasttouched = m->ticks;
return dp->len;
}
/*
* format a track
*/
static void
|
|
2001/1122
| |
floppyformat(FDrive *dp, Cmdbuf *cb)
|
|
1999/0415
| |
{
int cyl, h, sec;
ulong track;
uchar *buf, *bp;
FType *t;
/*
* set the type
*/
|
|
2001/1122
| |
if(cb->nf == 2){
|
|
1999/0415
| |
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
|
|
2001/1122
| |
if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){
|
|
1999/0415
| |
dp->t = t;
|
|
2001/0727
| |
floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
|
|
1999/0415
| |
break;
}
}
if(t >= &floppytype[nelem(floppytype)])
error(Ebadarg);
|
|
2001/1122
| |
} else if(cb->nf == 1){
|
|
1999/0415
| |
floppysetdef(dp);
t = dp->t;
|
|
2001/1122
| |
} else {
cmderror(cb, "invalid floppy format command");
SET(t);
|
|
1999/0415
| |
}
/*
* buffer for per track info
*/
buf = smalloc(t->sectors*4);
if(waserror()){
free(buf);
nexterror();
}
/* force a recalibrate to cylinder 0 */
dp->confused = 1;
if(!waserror()){
floppyon(dp);
poperror();
}
/*
* format a track at time
*/
for(track = 0; track < t->tracks*t->heads; track++){
cyl = track/t->heads;
h = track % t->heads;
/*
* seek to track, ignore errors
*/
floppyseek(dp, track*t->tsize);
dp->cyl = cyl;
dp->confused = 0;
/*
* set up the dma (dp->len may be trimmed)
*/
bp = buf;
for(sec = 1; sec <= t->sectors; sec++){
*bp++ = cyl;
*bp++ = h;
*bp++ = sec;
*bp++ = t->bcode;
}
if(waserror()){
dmaend(DMAchan);
nexterror();
}
if(dmasetup(DMAchan, buf, bp-buf, 0) < 0)
error(Eio);
/*
* start operation
*/
fl.ncmd = 0;
fl.cmd[fl.ncmd++] = Fformat;
fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
fl.cmd[fl.ncmd++] = t->bcode;
fl.cmd[fl.ncmd++] = t->sectors;
fl.cmd[fl.ncmd++] = t->fgpl;
fl.cmd[fl.ncmd++] = 0x5a;
if(floppycmd() < 0)
error(Eio);
/* Poll ready bits and transfer data */
floppyexec((char *)buf, bp-buf, 0);
/*
* give bus to DMA, floppyintr() will read result
*/
|
|
2001/1122
| |
floppywait(1);
|
|
1999/0415
| |
dmaend(DMAchan);
poperror();
/*
* check for errors
*/
if(fl.nstat < 7){
DPRINT("format: confused\n");
fl.confused = 1;
error(Eio);
}
if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
DPRINT("format: failed %ux %ux %ux\n",
fl.stat[0], fl.stat[1], fl.stat[2]);
dp->confused = 1;
error(Eio);
}
}
free(buf);
dp->confused = 1;
poperror();
}
static void
floppyintr(Ureg *)
{
switch(fl.cmd[0]&~Fmulti){
case Fread:
case Fwrite:
case Fformat:
case Fdumpreg:
floppyresult();
break;
case Fseek:
case Frecal:
default:
floppysense(); /* to clear interrupt */
break;
}
fl.ncmd = 0;
wakeup(&fl.r);
}
Dev floppydevtab = {
'f',
"floppy",
floppyreset,
devinit,
floppyattach,
floppywalk,
floppystat,
floppyopen,
devcreate,
floppyclose,
floppyread,
devbread,
floppywrite,
devbwrite,
devremove,
devwstat,
};
|
|
2001/1211
| |
#include "../pc/devfloppy.c"
|