OS作成
Qemuでfloppyの1セクタのreadに成功。
しかし、石叩きはむずかしい、というか資料が少ない。必要な情報としては
- 初期化
- 読み込む手順
が欲しいんだけどデータシートとか「パソコンのレガシィI/O活用大全isbn:9784789834339」には石の中のレジスタの詳細しか載っていない。と言う事でいろんなkernelのsourceとデータシートを見ながら書くことになるけどLinuxやらのkernelは肥大化しすぎてやりたいことのみを探すのが大変。
後、ソフトだとnanosecくらいで終わる処理がMortorとかの可動部はmsec〜secくらいの時間が掛かるのでそれをどのように待ってアクセスするなどのノウハウはsourceから読み取るしかない。
後でちょろっとDMAとFDCの叩き方をまとめとこう。
※実機ではResult Phase辺りで失敗する。推測ではFDCからのデータ読み込みに時間が掛かって今のMSRステータスのチェック回数が少ないよって感じかな。
追記
recalibrate(track 0 へのシーク)コマンド後のwaitで失敗している。
追記
specifyコマンド投入後に何らかのコマンド(recalibrate)を流す前にFDCの状態がbusyになってて失敗している模様。コマンド投入後に読めるデータ全て吸い出せばFDCの状態はreadyにならないんだろうか。。わからない。。。
floppy.c
/* * @File floppy.c * @Brief row floppy access * * @Author Sodex * @Revision 0.1 * @License suspension * @Date creae: 2007/05/02 update: 2007/05/03 * * Copyright (C) 2007 Sodex */ #include "io.h" #include "memory.h" #include "vga.h" #include "floppy.h" static void delay(int n); static void fdc_dma_start(); static void fdc_dma_stop(); static void init_dma_r(); static int fdc_cmd(const u_int8_t *cmd, const u_int8_t length); static int fdc_wait_msrStatus(u_int8_t mask, u_int8_t expected); static void fdc_motor_on(); static void fdc_motor_off(); static void fdc_recalibrate(); static void fdc_read_results(); static u_int8_t dma_databuf[DMA_DATABUF]; static struct _dma_trans { u_int32_t count; u_int32_t addr; } dma_trans; static struct FDC_RESULTS { u_int8_t gets; u_int8_t req_sense; u_int32_t status_count; u_int8_t status[10]; } fdc_results; static void delay(int n) { int i; for (i = 0; i < n; ++i) in8(IO_DELAY); } static void fdc_dma_start() { out8(DMA_SGL_MSK_SEC, 0x02); } static void fdc_dma_stop() { out8(DMA_SGL_MSK_SEC, 0x06); } void init_dma() { // DMAC reset out8(DMA_MSR_CLR_PRI, 0x00); out8(DMA_MSR_CLR_SEC, 0x00); // DMAC mode register setting out8(DMA_MOD_PRI, 0xc0); out8(DMA_MOD_SEC, 0x46); out8(DMA_SGL_MSK_PRI, 0x00); } static void init_dma_r() { fdc_dma_stop(); out8(DMA_MSR_CLR_SEC, 0x00); out8(DMA_CLR_FLP_SEC, 0); out8(DMA_MOD_SEC, 0x46); disableInterrupt(); out8(DMA_ADD_SEC, dma_trans.addr >> 0); out8(DMA_ADD_SEC, dma_trans.addr >> 8); out8(DMA_TOP, dma_trans.addr >> 16); out8(DMA_CNT_SEC, dma_trans.count >> 0); out8(DMA_CNT_SEC, dma_trans.count >> 8); enableInterrupt(); fdc_dma_start(); } static int fdc_cmd(const u_int8_t *cmd, const u_int8_t length) { int i; for (i=0; i<length; i++) { fdc_wait_msrStatus(MSR_RQM|MSR_DIO, MSR_RQM); out8(FDC_DAT, cmd[i]); } return TRUE; } static int fdc_wait_msrStatus(u_int8_t mask, u_int8_t expected) { u_int8_t status; int count = 0; do { status = in8(FDC_MSR); count++; } while (((status & mask) != expected) && (count < FDC_RESULT_MAXCOUNT)); if (count == FDC_RESULT_MAXCOUNT) return FALSE; return TRUE; } static void fdc_motor_on() { out8(FDC_DOR, 0x1c); } static void fdc_motor_off() { out8(FDC_DOR, 0x0c); } static void fdc_recalibrate() { u_int8_t cmd[] = {CMD_RECALIBRATE, CMD_SUB}; u_int8_t cmd_ret[] = {CMD_SIS}; u_int8_t result[FDC_RESULT_MAXCOUNT]; int i, status; if (fdc_cmd(cmd, sizeof(cmd)) != TRUE) { } /* get result */ fdc_cmd(cmd_ret, sizeof(cmd_ret)); for (i=0; i<FDC_RESULT_MAXCOUNT; i++) { status = in8(FDC_MSR); sysPrints("Recalibrate MSR:"); sysPrintBin(status); sysPrintc('\n'); if ((status & MSR_DIO) == 0) break; result[i] = in8(FDC_DAT); } if (!fdc_wait_msrStatus(0x10, 0x00)) { sysPrints("recalibrate last wait fail\n"); } } // FDC Read Result Phase static void fdc_read_results() { u_int8_t* msr = &(fdc_results.status[0]); u_int8_t status; int count; for (count = 0; count < FDC_RESULT_MAXCOUNT; count++) { status = in8(FDC_MSR); sysPrints("result phase FDC_MSR:"); sysPrintBin(status); sysPrintc('\n'); if ((status & (MSR_RQM|MSR_DIO)) == (MSR_RQM|MSR_DIO)) break; } if (count == FDC_RESULT_MAXCOUNT) { sysPrints("fdc result phase error 1\n"); return; } do { *msr = in8(FDC_DAT); msr++; for (count = 0; count < FDC_RESULT_MAXCOUNT; count++) { status = in8(FDC_MSR); if (status & MSR_RQM) break; } if (count == FDC_RESULT_MAXCOUNT) { sysPrints("fdc result phase error 2\n"); break; } sysPrints("FDC_DAT\n"); } while (status & MSR_DIO); } static void fdc_specify() { fdc_motor_on(); u_int8_t specify_cmd[] = {0x03, 0xc1, 0x10}; if (!fdc_cmd(specify_cmd, sizeof(specify_cmd))) { sysPrints("FDC sepcify cmd error\n"); return; } sysPrints("specify end\n"); fdc_motor_off(); } void init_fdc() { init_dma(); dma_trans.addr = (u_int32_t)&dma_databuf[0]; dma_trans.count = 512; init_dma_r(); out8(FDC_DOR, 0x0); out8(FDC_CCR, 0x0); out8(FDC_DOR, 0xc); fdc_specify(); } char *fdc_read(u_int8_t head, u_int8_t track, u_int8_t sector, u_int8_t length) { fdc_motor_on(); fdc_recalibrate(); u_int8_t cmd[] = { 0x6|0x40, // CMD_READ|MODE_MFM head << 2, // head track, // track head, // head sector, // sector length, // length sector, // end of sector 0x1b, // dummy GSR 0 // dummy STP }; fdc_cmd(cmd, sizeof(cmd)); fdc_dma_stop(); fdc_read_results(); // write the binary which we get from DMA int i; sysPrints("READ DATA:"); for (i = 0; i < 16; i++) { sysPrintBin(dma_databuf[i]); sysPrintc(' '); } sysPrintc('\n'); fdc_motor_off(); return NULL; }
floppy.h
#ifndef _FLOPPY_H #define _FLOPPY_H #define TRUE 1 #define FALSE 0 #define DMA_DATABUF 1024 #define FDC_RESULT_MAXCOUNT 0x10 #define DMA_ADD_SEC 0x04 //channel2 low address #define DMA_CNT_SEC 0x05 //channel2 count address #define DMA_TOP 0x81 //channel2 high address #define DMA_CMD_PRI 0xD0 #define DMA_CMD_SEC 0x08 #define DMA_REQ_PRI 0xD2 #define DMA_REQ_SEC 0x09 #define DMA_SGL_MSK_PRI 0xD4 #define DMA_SGL_MSK_SEC 0x0A #define DMA_MOD_PRI 0xD6 #define DMA_MOD_SEC 0x0B #define DMA_CLR_FLP_PRI 0x0C #define DMA_CLR_FLP_SEC 0xD8 #define DMA_MSR_CLR_PRI 0xDA #define DMA_MSR_CLR_SEC 0x0D #define DMA_CLR_MSK_PRI 0xDC #define DMA_CLR_MSK_SEC 0x0E #define DMA_ALL_MSK_PRI 0xDE #define DMA_ALL_MSK_SEC 0x0F #define FDC_SRA 0x3f0 // FDC status registerA (R) #define FDC_SRB 0x3f1 // FDC status registerB (R) #define FDC_DOR 0x3f2 // FDC Control register (R/W) #define FDC_MSR 0x3f4 // FDC Status register (R) #define FDC_DSR 0x3f4 // FDC data rate select register (W) #define FDC_DAT 0x3f5 // FDC Data (R/W) #define FDC_DIR 0x3f7 // FDC digital input register (R) #define FDC_CCR 0x3f7 // FDC configuration control register (W) #define MSR_RQM 0x80 #define MSR_DIO 0x40 /* FDC CMD */ #define CMD_RECALIBRATE 0x07 #define CMD_SEEK 0x0f #define CMD_SIS 0x08 // SIS = SENSE INTERRUPT STATUS #define CMD_READ 0x46 //MT=0,MF=1,SK=0 /* == FDC_CMD_SUB format == x x x x x HD US1 US0 x is anyone. HD is head number. US1 and US0 are drive number of FD. This cmd is used as the second byte of almost all command. */ #define CMD_SUB 0x00 //HD=0, US1 & US0 = 0 #define IO_DELAY 0x80 typedef struct _trans { u_int32_t count; u_int32_t addr; } trans; void init_dma(); void init_fdc(); char *fdc_read(u_int8_t head, u_int8_t track, u_int8_t sector, u_int8_t length); #endif /* _FLOPPY_H */