📄 dsk.c
字号:
break;
case 0x66: /* get volume serial number */
{
struct Gioc_media FAR *gioc = rp->r_gioc;
ret = getbpb(pddt);
if (ret != 0)
return (ret);
gioc->ioc_serialno = pddt->ddt_serialno;
fmemcpy(gioc->ioc_volume, pddt->ddt_volume, 11);
fmemcpy(gioc->ioc_fstype, pddt->ddt_fstype, 8);
}
break;
case 0x67: /* get access flag */
{
struct Access_info FAR *ai = rp->r_ai;
ai->AI_Flag = descflags & DF_NOACCESS ? 0 : 1; /* bit 9 */
}
break;
default:
return failure(E_CMD);
}
return S_DONE;
}
STATIC WORD blockio(rqptr rp, ddt * pddt)
{
ULONG start, size;
WORD ret;
UWORD done;
int action;
bpb *pbpb;
switch (rp->r_command)
{
case C_INPUT:
action = LBA_READ;
break;
case C_OUTPUT:
action = LBA_WRITE;
break;
case C_OUTVFY:
action = LBA_WRITE_VERIFY;
break;
default:
return failure(E_FAILURE);
}
if (pddt->ddt_descflags & DF_NOACCESS) /* drive inaccessible */
return failure(E_FAILURE);
tmark(pddt);
start = (rp->r_start != HUGECOUNT ? rp->r_start : rp->r_huge);
pbpb = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb;
size = (pbpb->bpb_nsize ? pbpb->bpb_nsize : pbpb->bpb_huge);
if (start >= size || start + rp->r_count > size)
{
return 0x0408;
}
start += pddt->ddt_offset;
ret = LBA_Transfer(pddt, action,
rp->r_trans,
start, rp->r_count, &done);
rp->r_count = done;
if (ret != 0)
{
return dskerr(ret);
}
return S_DONE;
}
STATIC WORD blk_error(rqptr rp, ddt * pddt)
{
UNREFERENCED_PARAMETER(pddt);
rp->r_count = 0;
return failure(E_FAILURE); /* general failure */
}
STATIC WORD blk_noerr(rqptr rp, ddt * pddt)
{
UNREFERENCED_PARAMETER(rp);
UNREFERENCED_PARAMETER(pddt);
return S_DONE;
}
STATIC WORD dskerr(COUNT code)
{
/* printf("diskette error:\nhead = %d\ntrack = %d\nsector = %d\ncount = %d\n",
head, track, sector, count); */
switch (code & 0x03)
{
case 1: /* invalid command - general failure */
if (code & 0x08)
return S_ERROR | E_NOTRDY; /* failure(E_NOTRDY); at least on yhe INT25 route,
0x8002 is returned */
else
return failure(E_CMD);
case 2: /* address mark not found - general failure */
return failure(E_FAILURE);
case 3: /* write protect */
return failure(E_WRPRT);
default:
if (code & 0x80) /* time-out */
return failure(E_NOTRDY);
else if (code & 0x40) /* seek error */
return failure(E_SEEK);
else if (code & 0x10) /* CRC error */
return failure(E_CRC);
else if (code & 0x04)
return failure(E_NOTFND);
else
return failure(E_FAILURE);
}
}
/*
translate LBA sectors into CHS addressing
*/
STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt)
{
/* we need the defbpb values since those are taken from the
BIOS, not from some random boot sector, except when
we're dealing with a floppy */
const bpb *pbpb = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb;
unsigned hs = pbpb->bpb_nsecs * pbpb->bpb_nheads;
unsigned hsrem = (unsigned)(LBA_address % hs);
LBA_address /= hs;
if (LBA_address > 1023ul)
{
#ifdef DEBUG
printf("LBA-Transfer error : cylinder %lu > 1023\n", LBA_address);
#else
put_string("LBA-Transfer error : cylinder > 1023\n");
#endif
return 1;
}
chs->Cylinder = (UWORD)LBA_address;
chs->Head = hsrem / pbpb->bpb_nsecs;
chs->Sector = hsrem % pbpb->bpb_nsecs + 1;
return 0;
}
/* Test for 64K boundary crossing and return count small */
/* enough not to exceed the threshold. */
STATIC unsigned DMA_max_transfer(void FAR * buffer, unsigned count)
{
unsigned dma_off = (UWORD)((FP_SEG(buffer) << 4) + FP_OFF(buffer));
unsigned sectors_to_dma_boundary = (dma_off == 0 ?
0xffff / SEC_SIZE :
(UWORD)(-dma_off) / SEC_SIZE);
return min(count, sectors_to_dma_boundary);
}
/*
int LBA_Transfer(
ddt *pddt, physical characteristics of drive
UWORD mode, LBA_READ/WRITE/WRITE_VERIFY/VERIFY
VOID FAR *buffer, user buffer
ULONG LBA_address, absolute sector address
unsigned totaltodo, number of sectors to transfer
UWORD *transferred sectors actually transferred
Read/Write/Write+verify some sectors, using LBA addressing.
This function handles all the minor details, including:
retry in case of errors
crossing the 64K DMA boundary
translation to CHS addressing if necessary
crossing track boundaries (necessary for some BIOS's
High memory doesn't work very well, use internal buffer
write with verify details for LBA
*/
STATIC int LBA_Transfer(ddt * pddt, UWORD mode, VOID FAR * buffer,
ULONG LBA_address, unsigned totaltodo,
UWORD * transferred)
{
static struct _bios_LBA_address_packet dap = {
16, 0, 0, 0, 0, 0, 0
};
unsigned count;
unsigned error_code = 0;
struct CHS chs;
void FAR *transfer_address;
unsigned char driveno = pddt->ddt_driveno;
int num_retries;
*transferred = 0;
/* only low-level format floppies for now ! */
if (mode == LBA_FORMAT && hd(pddt->ddt_descflags))
return 0;
/* optionally change from A: to B: or back */
play_dj(pddt);
if (!hd(pddt->ddt_descflags))
{
UBYTE FAR *int1e_ptr = (UBYTE FAR *)getvec(0x1e);
unsigned char nsecs = (unsigned char)(pddt->ddt_bpb.bpb_nsecs);
if (int1e_ptr[4] != nsecs)
{
int1e_ptr[4] = nsecs;
fl_reset(driveno);
}
}
/*
if (LBA_address+totaltodo > pddt->total_sectors)
{
printf("LBA-Transfer error : address overflow = %lu > %lu max\n",LBA_address+totaltodo,driveParam->total_sectors);
return 1;
}
*/
buffer = adjust_far(buffer);
for (; totaltodo != 0;)
{
/* avoid overflowing 64K DMA boundary */
count = DMA_max_transfer(buffer, totaltodo);
if (FP_SEG(buffer) >= 0xa000 || count == 0)
{
transfer_address = DiskTransferBuffer;
count = 1;
if ((mode & 0xff00) == (LBA_WRITE & 0xff00))
{
fmemcpy(DiskTransferBuffer, buffer, 512);
}
}
else
{
transfer_address = buffer;
}
for (num_retries = 0; num_retries < N_RETRY; num_retries++)
{
if ((pddt->ddt_descflags & DF_LBA) && mode != LBA_FORMAT)
{
dap.number_of_blocks = count;
dap.buffer_address = transfer_address;
dap.block_address_high = 0; /* clear high part */
dap.block_address = LBA_address; /* clear high part */
/* Load the registers and call the interrupt. */
if ((pddt->ddt_descflags & DF_WRTVERIFY) || mode != LBA_WRITE_VERIFY)
{
error_code = fl_lba_ReadWrite(driveno, mode, &dap);
}
else
{
/* verify requested, but not supported */
error_code =
fl_lba_ReadWrite(driveno, LBA_WRITE, &dap);
if (error_code == 0)
{
error_code =
fl_lba_ReadWrite(driveno, LBA_VERIFY, &dap);
}
}
}
else
{ /* transfer data, using old bios functions */
if (LBA_to_CHS(LBA_address, &chs, pddt))
return 1;
/* avoid overflow at end of track */
if (chs.Sector + count > (unsigned)pddt->ddt_bpb.bpb_nsecs + 1)
{
count = pddt->ddt_bpb.bpb_nsecs + 1 - chs.Sector;
}
error_code = (mode == LBA_READ ? fl_read :
mode == LBA_VERIFY ? fl_verify :
mode ==
LBA_FORMAT ? fl_format : fl_write) (driveno,
chs.Head,
chs.Cylinder,
chs.Sector,
count,
transfer_address);
if (error_code == 0 && mode == LBA_WRITE_VERIFY)
{
error_code = fl_verify(driveno, chs.Head, chs.Cylinder,
chs.Sector, count, transfer_address);
}
}
if (error_code == 0)
break;
fl_reset(driveno);
} /* end of retries */
if (error_code)
{
return error_code;
}
/* copy to user buffer if nesessary */
if (transfer_address == DiskTransferBuffer &&
(mode & 0xff00) == (LBA_READ & 0xff00))
{
fmemcpy(buffer, DiskTransferBuffer, 512);
}
*transferred += count;
LBA_address += count;
totaltodo -= count;
buffer = adjust_far((char FAR *)buffer + count * 512);
}
return (error_code);
}
/*
* Revision 1.17 2001/05/13 tomehlert
* Added full support for LBA hard drives
* initcode moved (mostly) to initdisk.c
* lower interface partly redesigned
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -