/**********************************************

	cache deiver Program

	1991.04.15	make by Ken

	compile use : cl /Zp /Ze

***********************************************/
#include    <stdio.h>
#include    <stdlib.h>
#include    <malloc.h>
#include    <dos.h>
#include    "defs.h"

typedef struct {
    char           mrk;
    unsigned int   psp;
    unsigned int   siz;
} MCB;

void	Dev_str_call(char far *ent,REQ far *req);
void	Dev_int_call(char far *ent);
DPB far	*get_DPB(int dev);

    DPB     far	*dpb;
    REQ     	req;
    int     use_count=0;
    int     lru_count=0;
    int	    fre_count=0;
    int     dev_use[MAX_DEV];

void	Cache_stat( void )
{
    int     i;
    SEC_PTR far *sp;
    ushort far  *lp;
    ushort far  *up;

    use_count = lru_count = fre_count = 0;
    for ( i = 0 ; i < MAX_DEV ; i++ )
	dev_use[i] = 0;

    lp = (ushort far *)req.x.ext.lru_tbl;
    up = (ushort far *)req.x.ext.use_tbl;

    for ( i = 0 ; i < MAX_HASH ; i++ ) {
	sp = (SEC_PTR far *)lp;
	FP_OFF(sp) = lp[i];
	while ( FP_OFF(sp) != 0 ) {
	    if ( sp->dev != FRE_DEV ) {
		dev_use[sp->dev]++;
		lru_count++;
	    } else
		fre_count++;
	    FP_OFF(sp) = (ushort)sp->next;
	}

	sp = (SEC_PTR far *)up;
	FP_OFF(sp) = up[i];
	while ( FP_OFF(sp) != 0 ) {
	    use_count++;
	    FP_OFF(sp) = (ushort)sp->next;
	}
    }
}
void	Device_call( void )
{
    char far *p;

    p = (char far *)(dpb->DevEnt);

    FP_OFF(p) = dpb->DevEnt->str_ent;
    Dev_str_call(p,(REQ far *)(&req));

    FP_OFF(p) = dpb->DevEnt->int_ent;
    Dev_int_call(p);
}
void	mcb_clear(ushort psp)
{
    unsigned int     u;
    union REGS       regs;
    struct SREGS     sregs;
    unsigned short far *p;
    MCB far	     *mcb;

    regs.h.ah = 0x52;
    int86x(0x21,&regs,&regs,&sregs);

    FP_OFF(p) = regs.x.bx - 2;
    FP_SEG(p) = sregs.es;

    FP_OFF(mcb) = 0;
    FP_SEG(mcb) = *p;

    for ( ; ; ) {
	if ( mcb->psp == psp )
	    mcb->psp = _psp;
	if ( mcb->mrk == 'Z' )
	    break;
	u = FP_SEG(mcb) + mcb->siz + 1;
	FP_SEG(mcb) = u;
    }

}
int	main(int argc,char *argv[])
{
    int     i,dev=(-1);
    int     out_flg = FALSE;
    char    *p;
    DPB far *dp;
    unsigned long far *lp;

    while ( --argc > 0 ) {
	p = *(++argv);
	if ( *p == '-' )
	    out_flg = TRUE;
	else
	    dev = toupper(*p) - 'A';
    }

    if ( dev < 0 ) {
	fprintf(stderr,"use: CMODE <Cache Buffer Device> [-]\n");
	return 1;
    }

    if ( (dpb = get_DPB(dev)) == NULL ) {
	fprintf(stderr,"Can't get DPB %c: Device\n",dev+'A');
	return 1;
    }

    req.len = 28;
    req.unit = dpb->UnitNum;
    req.cmds = (out_flg == FALSE ? 80:81);	/* Ext Cache Command */
    req.stat = 0;
    req.md_id = dpb->MedId;
    Device_call();

    if ( (req.stat & 0x8000) != 0 ) {
	fprintf(stderr,"Can't Cache Device %c:\n",dev+'A');
	return 1;
    }

    if ( out_flg != FALSE ) {
	mcb_clear(req.x.quit.psp_seg);
	printf("キャッシュを解除しました\n");

    } else {
	Cache_stat();

	printf("    キャッシュバッファデバイス名  %c\n",dev+'A');

	printf("    キャッシュしているデバイス名  ");
	lp = (unsigned long far *)req.x.ext.dpb_ptr;
	for ( i = 1 ; i < req.x.ext.max_dev ; i++ ) {
	    dp = (DPB far *)(lp[i]);
	    printf("%c ",dp->DrvNum+'A');
	}
	printf("\n");

	printf("        現在のキャッシュ動作状況  %s\n",
			req.x.ext.mode == FALSE ? "有効":"無効");

	i = use_count + lru_count + fre_count;
	printf("          全てのバッファセクタ数  %-4d (%dK)\n",i,
					(int)((long)i*dpb->SecLen/1024L));

	printf("  デバイスが使用しているセクタ数  %-4d (%dK)\n",use_count,
				(int)((long)use_count*dpb->SecLen/1024L));

	printf("キャッシュで使用しているセクタ数  %-4d (%dK)\n",lru_count,
				(int)((long)lru_count*dpb->SecLen/1024L));

	printf("              現在の空きセクタ数  %-4d (%dK)\n",fre_count,
				(int)((long)fre_count*dpb->SecLen/1024L));
    }

    return 0;
}
