/*------------------------------------------------------------------------*/
/* MMCv3/SDv1/SDv2 (SPIモード) 制御モジュール                             */
/* インターフェース 付録SH7262基板サンプルプログラム                      */
/*------------------------------------------------------------------------*/
/*
/  Copyright (C) 2010, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------*/


#include "SH7262.h"
#include "diskio.h"
//#include "monitor.h"

#define	_USE_CD		1	/* カード検出スイッチを使用 */
#define _USE_WP		0	/* ライトプロテクトスイッチを使用 */


/* MMC/SDコマンド */
#define CMD0	(0)			/* GO_IDLE_STATE */
#define CMD1	(1)			/* SEND_OP_COND (MMC) */
#define	ACMD41	(0x80+41)	/* SEND_OP_COND (SDC) */
#define CMD8	(8)			/* SEND_IF_COND */
#define CMD9	(9)			/* SEND_CSD */
#define CMD10	(10)		/* SEND_CID */
#define CMD12	(12)		/* STOP_TRANSMISSION */
#define ACMD13	(0x80+13)	/* SD_STATUS (SDC) */
#define CMD16	(16)		/* SET_BLOCKLEN */
#define CMD17	(17)		/* READ_SINGLE_BLOCK */
#define CMD18	(18)		/* READ_MULTIPLE_BLOCK */
#define CMD23	(23)		/* SET_BLOCK_COUNT (MMC) */
#define	ACMD23	(0x80+23)	/* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24	(24)		/* WRITE_BLOCK */
#define CMD25	(25)		/* WRITE_MULTIPLE_BLOCK */
#define CMD55	(55)		/* APP_CMD */
#define CMD58	(58)		/* READ_OCR */


/* MMC制御ポート・機能設定  (プラットフォーム依存定義) */

#define CS_LOW()	PGDR1 &= ~0x0010	/* MMC CS = L */
#define	CS_HIGH()	PGDR1 |=  0x0010	/* MMC CS = H */
#define SOCKPORT	PJPR0			/* ソケット状態入力(PJ) */
#define SOCKWP		0x0008			/* ライトプロテクト接点 (PJ3) */
#define SOCKINS		0x0002			/* カード検出接点 (PJ1) */

#define BCLK		48000000UL		/* SPIモジュール供給クロック */
#define CLK_FAST	24000000UL		/* SCLK高速 */
#define	CLK_SLOW	400000UL		/* SCLK低速 (初期化時) */
#define	DIV_F		(BCLK/CLK_FAST/2-1)
#define	DIV_S		(BCLK/CLK_SLOW/2-1)
#define	FCLK_SLOW()	{SPCR_0&=~0x40; SPBR_0=DIV_S; SPCR_0|=0x40;}	/* Set slow clock (100k-400k) */
#define	FCLK_FAST()	{SPCR_0&=~0x40; SPBR_0=DIV_F; SPCR_0|=0x40;}	/* Set fast clock (MMC:20MHz max, SD:25MHz max) */


/*--------------------------------------------------------------------------

   Module Private Functions

---------------------------------------------------------------------------*/

static volatile
DSTATUS Stat = STA_NOINIT;	/* ドライブステータス */

static volatile
BYTE Timer1, Timer2;	/* 100Hzタイマ (disk_timerproc()) */

static
BYTE CardType;			/* カードタイプ */



/*-----------------------------------------------------------------------*/
/* MMCへデータを送信  (プラットフォーム依存関数)                         */
/*-----------------------------------------------------------------------*/

/* 1バイト送信 */
static
void xmit_spi (
	BYTE dat	/* 送信するデータ */
)
{
	*(volatile BYTE*)&SPDR_0 = dat;	/* 送信開始 */
	while ((SPSR_0 & 0x80) == 0) ;	/* 転送終了待ち */
	*(volatile BYTE*)&SPDR_0;		/* 受信データは棄てる */
}

/* ブロック送信 */
static
void xmit_spi_multi (
	const BYTE *buff,	/* 送信データへのポインタ */
	UINT btx			/* 送信するバイト数 */
)
{
	*(volatile BYTE*)&SPDR_0 = *buff++;	/* 送信開始(パイプラインに1バイト分詰めておく) */
	btx--;

	do {
		*(volatile BYTE*)&SPDR_0 = *buff++;	/* 次のデータを送信 */
		while ((SPSR_0 & 0x80) == 0) ;		/* 1バイト転送待ち */
		*(volatile BYTE*)&SPDR_0;			/* 受信データを棄てる */
	} while (--btx);						/* データ数繰り返し */

	while ((SPSR_0 & 0x80) == 0) ;			/* 残った受信データを棄てる */
	*(volatile BYTE*)&SPDR_0;
}



/*-----------------------------------------------------------------------*/
/* MMCからデータを受信  (プラットフォーム依存関数)                       */
/*-----------------------------------------------------------------------*/

/* 1バイト受信 */
static
BYTE rcvr_spi (void)
{
	*(volatile BYTE*)&SPDR_0 = 0xFF;	/* 0xFF送信 */
	while ((SPSR_0 & 0x80) == 0) ;		/* 転送完了待ち */
	return *(volatile BYTE*)&SPDR_0;	/* 受信データを返す */
}

/* ブロック受信 */
static
void rcvr_spi_multi (
	BYTE *buff,		/* データ受信バッファへのポインタ */
	UINT btr		/* 受信するバイト数 */
)
{
	*(volatile BYTE*)&SPDR_0 = 0xFF;	/* 0xFF送信(パイプラインに1バイト分詰めておく) */
	btr--;

	do {
		*(volatile BYTE*)&SPDR_0 = 0xFF;	/* 0xFF送信 */
		while ((SPSR_0 & 0x80) == 0) ;		/* 受信待ち */
		*buff++ = *(volatile BYTE*)&SPDR_0;	/* 受信データをバッファにストア */
	} while (--btr);						/* データ数繰り返し */

	while ((SPSR_0 & 0x80) == 0) ;			/* 残ったデータをバッファにストア */
	*buff++ = *(volatile BYTE*)&SPDR_0;
}




/*-----------------------------------------------------------------------*/
/* カードのReady待ち                                                     */
/*-----------------------------------------------------------------------*/

static
int wait_ready (void)	/* 1:Ready, 0:タイムアウト */
{
	Timer2 = 50;	/* タイムアウト = 500ms */

	rcvr_spi();		/* 1バイト空読み(DO駆動遅延分) */
	do {
		if (rcvr_spi() == 0xFF) return 1;	/* Ready */
		/* このループは時間を要します. マルチタスク環境では適宜 rot_rdq()を挿入します. */
	} while (Timer2);	/* 0xFF受信かタイムアウトまでポーリング */

	return 0;	/* タイムアウト */
}



/*-----------------------------------------------------------------------*/
/* カードのディセレクトとSPIバス解放                                     */
/*-----------------------------------------------------------------------*/

static
void deselect (void)
{
	CS_HIGH();		/* CS = H */
	rcvr_spi();		/* 1バイト分のクロック */
}



/*-----------------------------------------------------------------------*/
/* カードを選択してReady待ち                                             */
/*-----------------------------------------------------------------------*/

static
int select (void)	/* 1:OK, 0:タイムアウト */
{
	CS_LOW();		/* CS = H */
	if (!wait_ready()) {	/* タイムアウトしたら失敗 */
		deselect();
		return 0;
	}
	return 1;
}



/*-----------------------------------------------------------------------*/
/* MMC/SDカード制御回路の操作 (プラットフォーム依存関数)                 */
/*-----------------------------------------------------------------------*/

static
void power_on (void)	/* MMC制御回路を使用可能にする */
{
	STBCR5 &= ~0x02;	/* SPI0モジュール有効化 */

	/* SPI0モジュールをI/Oピンに接続 */
	PFCR3 = 0x0003;						/* MISO0 */
	PFCR2 = (PFCR2 & 0x0F0F) | 0x3030;	/* RSPCK0,MOSI0 */
	PGIOR1 |= 0x0010; PGCR5 &= 0xFFF0;	/* MMC_CS */
	CS_HIGH();
	if (_USE_CD) {PJIOR0 &= 0xFFFD; PJCR0 &= 0xFF0F;}	/* MMC_CD */
	if (_USE_WP) {PJIOR0 &= 0xFFF7; PJCR0 &= 0x0FFF;}	/* MMC_WP */

	/* SPI0モジュールを初期化 */
	SPPCR_0 = 0;						/* アイドル値固定とループバックモード: 未使用 */
	SPSCR_0 = 0;						/* シーケンス制御: 未使用 */
	SPDCR_0 = 0x20;						/* FIFOアクセス幅: バイト */
	SPBFCR_0 = 0xF0; SPBFCR_0 = 0x30;	/* FIFO初期化 */
	SPCMD_00 = 0x0700;					/* SPIモード: MODE0, 8bit, MSB first */
	SPCR_0 = 0x48;						/* SPIイネーブル(マスタモード) */
}


static
void power_off (void)	/* MMC制御回路の使用を終了する */
{
	select();			/* カードの内部処理終了待ち */
	deselect();

	SPCR_0 = 0;			/* SPI0モジュールのディセーブル */
	STBCR5 |= 0x02;		/* SPI0モジュール無効化 */
}



/*-----------------------------------------------------------------------*/
/* MMCからデータパケットを受信                                           */
/*-----------------------------------------------------------------------*/

static
int rcvr_datablock (	/* 1:OK, 0:エラー */
	BYTE *buff,			/* 受信データをストアするバッファ */
	UINT btr			/* データブロック長 */
)
{
	BYTE token;


	Timer1 = 20;
	do {							/* DataStartトークンを待つ (タイムアウト=200ms) */
		token = rcvr_spi();
		/* このループは時間を要します. マルチタスク環境では適宜 rot_rdq()を挿入します. */
	} while ((token == 0xFF) && Timer1);
	if(token != 0xFE) return 0;		/* 無効なDataStartトークンのときは失敗 */

	rcvr_spi_multi(buff, btr);		/* 続くデータをバッファにストア */
	rcvr_spi(); rcvr_spi();			/* CRCを棄てる */

	return 1;						/* 受信OK */
}



/*-----------------------------------------------------------------------*/
/* データパケットをMMCに送信                                             */
/*-----------------------------------------------------------------------*/

#if _READONLY == 0
static
int xmit_datablock (	/* 1:OK, 0:失敗 */
	const BYTE *buff,	/* 送信する512バイトのデータへのポインタ */
	BYTE token			/* 使用するトークン */
)
{
	BYTE resp;


	if (!wait_ready()) return 0;		/* Ready待ち(タイムアウトしたら失敗) */

	xmit_spi(token);					/* トークンを送信 */
	if (token != 0xFD) {				/* StopTranトークン以外のときはデータを送信 */
		xmit_spi_multi(buff, 512);		/* データ */
		xmit_spi(0xFF); xmit_spi(0xFF);	/* ダミーCRC */

		resp = rcvr_spi();				/* データレスポンスを受信 */
		if ((resp & 0x1F) != 0x05)		/* 受け付けられなかったらエラー */
			return 0;
	}
	return 1;
}
#endif /* _READONLY */



/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC                                          */
/*-----------------------------------------------------------------------*/

static
BYTE send_cmd (		/* 戻り値: R1レスポンス (bit7==1:送信失敗) */
	BYTE cmd,		/* コマンドインデックス */
	DWORD arg		/* 引数 */
)
{
	BYTE n, res;


	if (cmd & 0x80) {	/* ACMD<n>のときは先にCMD55を送る */
		cmd &= 0x7F;
		res = send_cmd(CMD55, 0);
		if (res > 1) return res;
	}

	/* カードを選択 */
	deselect();
	if (!select()) return 0xFF;

	/* Send command packet */
	xmit_spi(0x40 | cmd);				/* コマンドインデックス */
	xmit_spi((BYTE)(arg >> 24));		/* 引数[31..24] */
	xmit_spi((BYTE)(arg >> 16));		/* 引数[23..16] */
	xmit_spi((BYTE)(arg >> 8));			/* 引数[15..8] */
	xmit_spi((BYTE)arg);				/* 引数[7..0] */
	n = 0x01;							/* ダミーCRC + Stop */
	if (cmd == CMD0) n = 0x95;			/* 有効なCRC (CMD0(0)) */
	if (cmd == CMD8) n = 0x87;			/* 有効なCRC (CMD8(0x1AA)) */
	xmit_spi(n);

	/* コマンドレスポンス受信 */
	if (cmd == CMD12) rcvr_spi();		/* CMD12のときは直後の1バイトを棄てる */
	n = 10;								/* レスポンス待ち(最大10バイト) */
	do
		res = rcvr_spi();
	while ((res & 0x80) && --n);

	return res;							/* 得られたレスポンスを返す */
}



/*--------------------------------------------------------------------------

   Public Functions

---------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------*/
/* ディスクドライブの初期化                                              */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE drv		/* 物理ドライブ番号 (0) */
)
{
	BYTE n, cmd, ty, ocr[4];


	if (drv) return STA_NOINIT;			/* シングルドライブのみサポート */
	if (Stat & STA_NODISK) return Stat;	/* ソケットが空? */

	power_on();							/* MMC制御回路の初期化 */
	FCLK_SLOW();						/* 低速クロック */
	for (n = 10; n; n--) rcvr_spi();	/* ダミークロック送信 */

	ty = 0;
	if (send_cmd(CMD0, 0) == 1) {			/* カードをSPIモード/Idle状態に移行 */
		Timer1 = 100;						/* 処理タイムアウト:1秒 */
		if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDv2か? */
			/* たぶんSDv2 */
			for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();		/* R7 respの戻り値を受信 */
			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {				/* カードは2.7-3.6Vで動作可能か? */
				while (Timer1 && send_cmd(ACMD41, 1UL << 30)) ;	/* 初期化終了を待つ(ACMD41(HCS)) */
				if (Timer1 && send_cmd(CMD58, 0) == 0) {		/* OCRを読んでCCSビットをチェック */
					for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
					ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;	/* SDv2アドレッシングモード判定 */
				}
			}
		} else {
			/* SDv2以外 */
			if (send_cmd(ACMD41, 0) <= 1) 	{	/* SDv1かMMCか? */
				ty = CT_SD1; cmd = ACMD41;	/* SDv1 (ACMD41(0)) */
			} else {
				ty = CT_MMC; cmd = CMD1;	/* MMCv3 (CMD1(0)) */
			}
			while (Timer1 && send_cmd(cmd, 0)) ;		/* 初期化終了を待つ */
			if (!Timer1 || send_cmd(CMD16, 512) != 0)	/* 念のためブロック長を512に設定 */
				ty = 0;
		}
	}
	CardType = ty;	/* カードタイプフラグ */
	deselect();

	if (ty) {			/* 初期化成功 */
		FCLK_FAST();			/* 高速クロック */
		Stat &= ~STA_NOINIT;	/* ステータスのSTA_NOINITをクリア */
	} else {			/* 初期化失敗 */
		power_off();
		Stat = STA_NOINIT;
	}

	return Stat;
}



/*-----------------------------------------------------------------------*/
/* ディスクステータスの取得                                              */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE drv		/* 物理ドライブ番号 (0) */
)
{
	if (drv) return STA_NOINIT;		/* シングルドライブのみサポート */

	return Stat;	/* ディスクステータスを返す */
}



/*-----------------------------------------------------------------------*/
/* データの読み出し                                                      */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE drv,		/* 物理ドライブ番号 (0) */
	BYTE *buff,		/* データバッファへのポインタ */
	DWORD sector,	/* 読み出し開始セクタ番号 (LBA) */
	BYTE count		/* 読み出すセクタ数 (1..255) */
)
{
	if (drv || !count) return RES_PARERR;		/* パラメータが有効かチェック */
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* ドライブが動作可能かチェック */

	if (!(CardType & CT_BLOCK)) sector *= 512;	/* アドレッシングモードをカードに合わせる */

	if (count == 1) {	/* シングルブロック読み出し */
		if ((send_cmd(CMD17, sector) == 0)	/* READ_SINGLE_BLOCK */
			&& rcvr_datablock(buff, 512))
			count = 0;
	}
	else {				/* マルチブロック読み出し */
		if (send_cmd(CMD18, sector) == 0) {	/* READ_MULTIPLE_BLOCK */
			do {
				if (!rcvr_datablock(buff, 512)) break;
				buff += 512;
			} while (--count);
			send_cmd(CMD12, 0);				/* STOP_TRANSMISSION */
		}
	}
	deselect();

	return count ? RES_ERROR : RES_OK;	/* 結果を返す */
}



/*-----------------------------------------------------------------------*/
/* データの書き込み                                                      */
/*-----------------------------------------------------------------------*/

#if _READONLY == 0
DRESULT disk_write (
	BYTE drv,			/* 物理ドライブ番号 (0) */
	const BYTE *buff,	/* 書き込むデータへのポインタ */
	DWORD sector,		/* 書き込み開始セクタ番号 (LBA) */
	BYTE count			/* 書き込むセクタ数 (1..255) */
)
{
	if (drv || !count) return RES_PARERR;		/* パラメータが有効かチェック */
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* ドライブが動作可能かチェック */
	if (Stat & STA_PROTECT) return RES_WRPRT;	/* ドライブが書き込み可能かチェック */

	if (!(CardType & CT_BLOCK)) sector *= 512;	/* アドレッシングモードをカードに合わせる */

	if (count == 1) {	/* シングルブロック書き込み */
		if ((send_cmd(CMD24, sector) == 0)	/* WRITE_BLOCK */
			&& xmit_datablock(buff, 0xFE))
			count = 0;
	}
	else {				/* マルチブロック書き込み */
		if (CardType & CT_SDC) send_cmd(ACMD23, count);
		if (send_cmd(CMD25, sector) == 0) {	/* WRITE_MULTIPLE_BLOCK */
			do {
				if (!xmit_datablock(buff, 0xFC)) break;
				buff += 512;
			} while (--count);
			if (!xmit_datablock(0, 0xFD))	/* STOP_TRAN token */
				count = 1;
		}
	}
	deselect();

	return count ? RES_ERROR : RES_OK;	/* 結果を返す */
}
#endif /* _READONLY == 0 */



/*-----------------------------------------------------------------------*/
/* その他のドライブ制御                                                  */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL != 0
DRESULT disk_ioctl (
	BYTE drv,		/* 物理ドライブ番号 (0) */
	BYTE ctrl,		/* 制御コード */
	void *buff		/* 制御データへのポインタ */
)
{
	DRESULT res;
	BYTE n, csd[16], *ptr = buff;
	WORD csize;


	if (drv) return RES_PARERR;					/* パラメータが有効かチェック */
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* ドライブが動作可能かチェック */

	res = RES_ERROR;

	switch (ctrl) {
	case CTRL_SYNC :		/* ドライブの内部処理完了を待つ */
		if (select()) {
			deselect();
			res = RES_OK;
		}
		break;

	case GET_SECTOR_COUNT :	/* ドライブ容量(セクタ数)を返す (DWORD) */
		if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
			if ((csd[0] >> 6) == 1) {	/* SDC ver 2.00 */
				csize = csd[9] + ((WORD)csd[8] << 8) + 1;
				*(DWORD*)buff = (DWORD)csize << 10;
			} else {					/* SDC ver 1.XX or MMC ver 3 */
				n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
				csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
				*(DWORD*)buff = (DWORD)csize << (n - 9);
			}
			res = RES_OK;
		}
		break;

	case GET_SECTOR_SIZE :	/* セクタサイズ(バイト数)を返す (WORD) */
		*(WORD*)buff = 512;
		res = RES_OK;
		break;

	case GET_BLOCK_SIZE :	/* 消去ブロックサイズ(セクタ数)を返す (DWORD) */
		if (CardType & CT_SD2) {	/* SDC ver 2.00 */
			if (send_cmd(ACMD13, 0) == 0) {	/* Read SD status */
				rcvr_spi();
				if (rcvr_datablock(csd, 16)) {				/* Read partial block */
					for (n = 64 - 16; n; n--) rcvr_spi();	/* Purge trailing data */
					*(DWORD*)buff = 16UL << (csd[10] >> 4);
					res = RES_OK;
				}
			}
		} else {					/* SDC ver 1.XX or MMC */
			if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {	/* Read CSD */
				if (CardType & CT_SD1) {	/* SDC ver 1.XX */
					*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
				} else {					/* MMC */
					*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
				}
				res = RES_OK;
			}
		}
		break;

	/* 以降のioctlコマンドはFatFsでは使用しない */

	case MMC_GET_TYPE :		/* カードタイプを返す (BYTE) */
		*ptr = CardType;
		res = RES_OK;
		break;

	case MMC_GET_CSD :		/* CSDを読み出す (16バイト) */
		if (send_cmd(CMD9, 0) == 0		/* READ_CSD */
			&& rcvr_datablock(ptr, 16))
			res = RES_OK;
		break;

	case MMC_GET_CID :		/* CIDを読み出す (16バイト) */
		if (send_cmd(CMD10, 0) == 0		/* READ_CID */
			&& rcvr_datablock(ptr, 16))
			res = RES_OK;
		break;

	case MMC_GET_OCR :		/* OCRを読み出す (4バイト) */
		if (send_cmd(CMD58, 0) == 0) {	/* READ_OCR */
			for (n = 4; n; n--) *ptr++ = rcvr_spi();
			res = RES_OK;
		}
		break;

	case MMC_GET_SDSTAT :	/*SDステータスを読み出す (64バイト) */
		if (send_cmd(ACMD13, 0) == 0) {	/* SD_STATUS */
			rcvr_spi();
			if (rcvr_datablock(ptr, 64))
				res = RES_OK;
		}
		break;

	default:
		res = RES_PARERR;
	}

	deselect();

	return res;
}
#endif /* _USE_IOCTL != 0 */


/*-----------------------------------------------------------------------*/
/* タイマ割り込み処理  (プラットフォーム依存関数)                        */
/*-----------------------------------------------------------------------*/
/* この関数はタイマ割り込み処理の中から毎秒100回呼び出され、カード制御の
/  タイミングを得たりカード交換の検出などを行う。
*/

void disk_timerproc (void)
{
	static WORD pv;
	BYTE n, s;


	n = Timer1;						/* 100Hz減算タイマ(0停止) */
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;

	n = pv;
	pv = SOCKPORT & (SOCKWP | SOCKINS);	/* ソケット状態のサンプリング */

	if (n == pv) {					/* 接点状態は安定したか? */
		s = Stat;
		if (_USE_WP && (pv & SOCKWP))	/* WP == H (書き込み禁止) */
			s |= STA_PROTECT;
		else							/* WP == L (書き込み許可) */
			s &= ~STA_PROTECT;

		if (_USE_CD && (pv & SOCKINS))	/* CD == H (カードなし) */
			s |= (STA_NODISK | STA_NOINIT);
		else							/* CD == L (カードあり) */
			s &= ~STA_NODISK;

		Stat = s;
	}
}

