/* <fdc.c> */

#define ADR_FDC_DMAC	0x00400000

struct FIFO32 *fdc_fifo;
struct TASK *task_fdc;
struct FDC_STAT {
	int motorman;
	int result, cylinder;
} fdc_stat;

void inthandler26(int *esp)
/* FDCからの割り込み */
{
    io_in8(0x03f4); /* から読み:IRQにCPUが気づいたことをFDCへ教えてあげる */
    io_out8(PIC0_OCW2, 0x66); /* IRQ-06を終了 */
    fifo32_put(fdc_fifo, 3);
    return;
}

void motor_on(void)
{
	struct TIMER *timer;
	struct FIFO32 fifo;
	int fifo_buf[32];
	fifo32_init(&fifo, 32, fifo_buf, task_fdc);
	timer = timer_alloc();
	timer_init(timer, &fifo, 1);

	if (fdc_stat.motorman == 0) {
		/* モーターON */
		io_out8(0x03f2, 0x1c);
		timer_settime(timer, 125);
		while (fifo32_status(&fifo) == 0) { task_sleep(task_fdc); }
		fifo32_get(&fifo);	// 空読み
		fdc_stat.motorman = 1;
	}
	return;
}

void fdc_sendcommand(int data)
{
	/* FDCにコマンドを送る */
	while((io_in8(0x03f4) & 0xc0) != 0x80);
	io_out8(0x03f5, data);
	return;
}

int fdc_receivedata(void)
{
	while((io_in8(0x03f4) & 0xc0) != 0xc0);
	return io_in8(0x03f5);
}

void fdc_getstatus(void)
{
	int i;
	while((io_in8(0x03f4) & 0x10) != 0) { task_sleep(task_fdc); }	// コマンド送信準備
	fdc_sendcommand(0x08);
	i = fdc_receivedata() & 0xc0;
	if (i == 0x00) {
		/* 正常終了 */
		fdc_stat.result = 1;
	} else if (i == 0x40) {
		/* 異常終了 */
		fdc_stat.result = 2;
	} else {
		/* OSのバグと見ていい */
		fdc_stat.result = 3;
	}
	fdc_stat.cylinder = fdc_receivedata();
	return;
}

void fdc_seek0(void)
{
	motor_on();
	while((io_in8(0x03f4) & 0x11) != 0) { task_sleep(task_fdc); }	// 送信準備
	fdc_sendcommand(0x07);
	fdc_sendcommand(0x00);
	while (fifo32_status(fdc_fifo) == 0) { task_sleep(task_fdc); }	// 割り込み待ち
	fifo32_get(fdc_fifo);
	fdc_getstatus();
	return;
}

void fdc_seek(int h, int c)
{
	motor_on();
	while((io_in8(0x03f4) & 0x11) != 0) { task_sleep(task_fdc); }	// 送信準備
	fdc_sendcommand(0x0f);
	fdc_sendcommand(h<<2);
	fdc_sendcommand(c);
	while (fifo32_status(fdc_fifo) == 0) { task_sleep(task_fdc); }	// 割り込み待ち
	fifo32_get(fdc_fifo);
	fdc_getstatus();
	return;
}

void fdc_read(int sector, int size, int addr, struct FIFO32 *fifo, int retbase) {
	io_cli();
	fifo32_put(&task_fdc->fifo, 1);
	fifo32_put(&task_fdc->fifo, sector);
	fifo32_put(&task_fdc->fifo, size);
	fifo32_put(&task_fdc->fifo, addr);
	io_sti();
	fifo32_put(fifo, retbase + fdc_stat.result);
	return;
}

void fdc_task(void)
{
	int i, j, k, l;
	int data[7], c, h, s;
	struct TIMER *timer;
	timer = timer_alloc();
	timer_init(timer, &task_fdc->fifo, 4);

	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	char str[30];
	// putfonts((unsigned int *)(binfo->vram), binfo->scrnx, 0, 0, 0xffffff, "@");

	io_out8(0x00d6, 0xc0); /* マスタのch0をカスケードモードに */
	io_out8(0x00c0, 0x00); /* スレーブのDMAを許可 */
	io_out8(0x000a, 0x06); /* マスタのch2のDMAをマスク */

	for (;;) {
		io_cli();
		if (fifo32_status(&task_fdc->fifo) == 0) {
			if (fdc_stat.motorman == 1) {
				/* 「モーターOFFしてもいいですか。」 */
				timer_settime(timer, 300);	// 3秒待つ。
			}
			task_sleep(task_fdc);
			io_sti();
		} else {
			i = fifo32_get(&task_fdc->fifo);
			io_sti();
			if (i == 1) {
				/* データリード */
				/* 動いてるか知らんけどタイマーキャンセル */
				timer_cancel(timer);
				/* FIFOからコマンドを3個取得する */
				for (j = 0; j < 3; j++) {
					data[j] = fifo32_get(&task_fdc->fifo);
				}
				c = data[0] / 36;							/* セクタ */
				h = (data[0] - c * 2) / 18;					/* ヘッダ */
				s = data[0] - c - h + 1;					/* セクタ */
/*
j = fdc_stat.cylinder;
sprintf(str, "r=%d c=%d", fdc_stat.result, fdc_stat.cylinder);
putfonts((unsigned int *) (binfo->vram), binfo->scrnx, 280, 0, 0xffffff, str);
*/
				/* DMACの設定 */
				io_out8(0x000b, 0x06);						/* モード設定:デマンド・アドレス増加方向・メモリへの書き込み・ch2 */
				io_out8(0x0005, 0xff);						/* バイト数の設定 */
				io_out8(0x0005, data[1] * 2 - 1);
				io_out8(0x0004, data[2] & 0xff);			/* メモリ番地の設定 */
				io_out8(0x0004, (data[2] >> 8) & 0xff); 
				io_out8(0x0081, (data[2] >> 16) & 0xff);
				io_out8(0x000a, 0x02);						/* マスタのch2のDMAをマスク解除 */
				/* コマンド送信アタタタタタ!!! */
				for (k = 0; k < 2; k++) {
					fdc_seek(h, c);
					for (j = 0; j < 5; j++) {
						while((io_in8(0x03f4) & 0x11) != 0) { task_sleep(task_fdc); }	// 送信準備
						fdc_sendcommand(0xE6);	// 読み込みコマンド
						fdc_sendcommand(h<<2);	// ヘッダ<<2
						fdc_sendcommand(c);		// シリンダ
						fdc_sendcommand(h);		// ヘッダ
						fdc_sendcommand(s);		// セクタ
						fdc_sendcommand(0x02);	// 以下おまじない
						fdc_sendcommand(0x12);
						fdc_sendcommand(0x01);
						fdc_sendcommand(0xFF);	// 以上!
						/* 割り込み待ち */
						while (fifo32_status(fdc_fifo) == 0) { task_sleep(task_fdc); }
						fifo32_get(fdc_fifo);
						/* データ受け取り・簡易判定 */
						for (l = 0; l < 7; l++) {
							data[l] = fdc_receivedata();
						}
						data[0] = data[0] & 0xc0;
						if (data[0] == 0x00) {
							break;
						}
putfonts((unsigned int *) (binfo->vram), binfo->scrnx, 280 + j * 8, k * 16, 0xffffff, "*");
					}
					if (data[0] == 0x00) {
						break;
					} else if (data[0] != 0x00 && k != 0) {
						/* 1回目の挑戦で、5回ともエラーだったので
												シークからやり直し */
						fdc_seek0();
					}
				}
				if (data[0] == 0x00) {
					/* 正常終了 */
					fdc_stat.result = 1;
				} else if (data[0] == 0x40) {
					/* 異常終了 */
					fdc_stat.result = 2;
				} else {
					/* OSのバグと見ていい */
					fdc_stat.result = 3;
				}
				if (data[6] != 0x02) {
					/* エラー */
					fdc_stat.result = 4;
				}
fdc_stat.cylinder = data[3];
sprintf(str, "r=%d(0x%02x) c=%d h=%d s=%d", fdc_stat.result, data[0], fdc_stat.cylinder, data[4], data[5]);
putfonts((unsigned int *) (binfo->vram), binfo->scrnx, 280, 32, 0xffffff, str);

				io_out8(0x000a, 0x06); /* マスタのch2のDMAをマスク */
			}
			if (i == 2) {
				/* データライト */
				/* 動いてるか知らんけどタイマーキャンセル */
				timer_cancel(timer);
			}
			if (i == 4) {
				/* FDDモーターOFF */
				io_out8(0x03f2, 0x0c);
				fdc_stat.motorman = 0;
			}
		}
	}
}

void fdc_init(struct MEMMAN *memman)
{
	int *fdc_taskfifobuf = (int *) memman_alloc_4k(memman, 1024 * 4);
	int fdc_fifobuf[32];
	task_fdc = task_alloc();
	task_fdc->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
	task_fdc->tss.eip = (int) &fdc_task;
	task_fdc->tss.es = 1 * 8;
	task_fdc->tss.cs = 2 * 8;
	task_fdc->tss.ss = 1 * 8;
	task_fdc->tss.ds = 1 * 8;
	task_fdc->tss.fs = 1 * 8;
	task_fdc->tss.gs = 1 * 8;
	task_run(task_fdc, 2, 2);
	fifo32_init(&task_fdc->fifo, 1024, fdc_taskfifobuf, task_fdc);	// コマンド・タイマー
	fifo32_init(fdc_fifo, 32, fdc_fifobuf, task_fdc);				// 割り込み
	fdc_stat.motorman = 0;
	return;
}

/* </fdc.c> */


Wikiの [ 一覧一覧 最終更新最終更新 ヘルプヘルプ   RSSRSS]