400 lines
10 KiB
C
400 lines
10 KiB
C
#include "../include/floppy.h"
|
||
#include "../include/task.h"
|
||
#include "../include/printf.h"
|
||
#include "../include/vdisk.h"
|
||
#include "../include/io.h"
|
||
#include "../include/dma.h"
|
||
|
||
struct task_struct *floppy_use;
|
||
struct task_struct *waiter;
|
||
volatile int floppy_int_count = 0;
|
||
|
||
static volatile int done = 0;
|
||
static int dchange = 0;
|
||
static int motor = 0;
|
||
static int mtick = 0;
|
||
static volatile int tmout = 0;
|
||
static unsigned char status[7] = {0};
|
||
static unsigned char statsz = 0;
|
||
static unsigned char sr0 = 0;
|
||
static unsigned char fdc_track = 0xff;
|
||
static DrvGeom geometry = {DG144_HEADS, DG144_TRACKS, DG144_SPT};
|
||
unsigned long tbaddr = 0x80000L;
|
||
|
||
static void Read(char drive, unsigned char *buffer, unsigned int number,
|
||
unsigned int lba) {
|
||
floppy_use = get_current();
|
||
for (int i = 0; i < number; i += SECTORS_ONCE) {
|
||
int sectors = ((number - i) >= SECTORS_ONCE) ? SECTORS_ONCE : (number - i);
|
||
fdc_rw(lba + i, buffer + i * 512, 1, sectors);
|
||
}
|
||
floppy_use = NULL;
|
||
}
|
||
|
||
static void Write(char drive, unsigned char *buffer, unsigned int number,
|
||
unsigned int lba) {
|
||
floppy_use = get_current();
|
||
for (int i = 0; i < number; i += SECTORS_ONCE) {
|
||
int sectors = ((number - i) >= SECTORS_ONCE) ? SECTORS_ONCE : (number - i);
|
||
fdc_rw(lba + i, buffer + i * 512, 0, sectors);
|
||
}
|
||
floppy_use = NULL;
|
||
}
|
||
|
||
void init_floppy() {
|
||
sendbyte(CMD_VERSION); //发送命令(获取软盘版本),如果收到回应,说明软盘正在工作
|
||
if (getbyte() == -1) {
|
||
printf("floppy: no floppy drive found\n");
|
||
printf("No fount FDC\n");
|
||
return;
|
||
}
|
||
|
||
register_interrupt_handler(0x26,flint);
|
||
|
||
printf("[\035floppy\036]: FLOPPY DISK:RESETING\n");
|
||
reset(); //重置软盘驱动器
|
||
printf("[\035floppy\036]:FLOPPY DISK:reset over!\n");
|
||
sendbyte(CMD_VERSION); //获取软盘版本
|
||
printf("[\035floppy\036]:FDC_VER:0x%x\n", getbyte()); //并且输出到屏幕上
|
||
vdisk vd;
|
||
strcpy(vd.DriveName, "floppy");
|
||
vd.Read = Read;
|
||
vd.Write = Write;
|
||
vd.size = 1474560;
|
||
vd.flag = 1;
|
||
register_vdisk(vd);
|
||
}
|
||
|
||
int fdc_rw_ths(int track,
|
||
int head,
|
||
int sector,
|
||
unsigned char* blockbuff,
|
||
int read,
|
||
unsigned long nosectors) {
|
||
// 跟上面的大同小异
|
||
int tries, copycount = 0;
|
||
unsigned char* p_tbaddr = (char*)0x80000;
|
||
unsigned char* p_blockbuff = blockbuff;
|
||
|
||
motoron();
|
||
|
||
if (!read && blockbuff) {
|
||
for (copycount = 0; copycount < (nosectors * 512); copycount++) {
|
||
*p_tbaddr = *p_blockbuff;
|
||
p_blockbuff++;
|
||
p_tbaddr++;
|
||
}
|
||
}
|
||
|
||
for (tries = 0; tries < 3; tries++) {
|
||
if (io_in8(FDC_DIR) & 0x80) {
|
||
dchange = 1;
|
||
seek(1);
|
||
recalibrate();
|
||
motoroff();
|
||
|
||
return fdc_rw_ths(track, head, sector, blockbuff, read, nosectors);
|
||
}
|
||
if (!seek(track)) {
|
||
motoroff();
|
||
return 0;
|
||
}
|
||
|
||
io_out8(FDC_CCR, 0);
|
||
|
||
if (read) {
|
||
dma_xfer(2, tbaddr, nosectors * 512, 0);
|
||
sendbyte(CMD_READ);
|
||
} else {
|
||
dma_xfer(2, tbaddr, nosectors * 512, 1);
|
||
sendbyte(CMD_WRITE);
|
||
}
|
||
|
||
sendbyte(head << 2);
|
||
sendbyte(track);
|
||
sendbyte(head);
|
||
sendbyte(sector);
|
||
sendbyte(2);
|
||
sendbyte(geometry.spt);
|
||
|
||
if (geometry.spt == DG144_SPT)
|
||
sendbyte(DG144_GAP3RW);
|
||
else
|
||
sendbyte(DG168_GAP3RW);
|
||
sendbyte(0xff);
|
||
|
||
wait_floppy_interrupt();
|
||
|
||
if ((status[0] & 0xc0) == 0)
|
||
break;
|
||
|
||
recalibrate();
|
||
}
|
||
|
||
motoroff();
|
||
|
||
if (read && blockbuff) {
|
||
p_blockbuff = blockbuff;
|
||
p_tbaddr = (char*)0x80000;
|
||
for (copycount = 0; copycount < (nosectors * 512); copycount++) {
|
||
*p_blockbuff = *p_tbaddr;
|
||
p_blockbuff++;
|
||
p_tbaddr++;
|
||
}
|
||
}
|
||
|
||
return (tries != 3);
|
||
}
|
||
|
||
int write_floppy_for_ths(int track,
|
||
int head,
|
||
int sec,
|
||
unsigned char* blockbuff,
|
||
unsigned long nosec) {
|
||
int res = fdc_rw_ths(track, head, sec, blockbuff, 0, nosec);
|
||
}
|
||
|
||
void flint(registers_t *reg) {
|
||
floppy_int_count =
|
||
1; // 设置中断计数器为1,代表中断已经发生(或者是系统已经收到了中断)
|
||
io_out8(0x20, 0x20); // 发送EOI信号,告诉PIC,我们已经处理完了这个中断
|
||
//task_run(waiter);
|
||
// task_next();
|
||
}
|
||
|
||
void sendbyte(int byte) {
|
||
volatile int msr;
|
||
int tmo; // 超时计数器
|
||
|
||
for (tmo = 0; tmo < 128; tmo++) // 这里我们只给128次尝试的机会
|
||
{
|
||
msr = io_in8(FDC_MSR);
|
||
if ((msr & 0xc0) ==
|
||
0x80) {
|
||
io_out8(FDC_DATA, byte);
|
||
return;
|
||
}
|
||
io_in8(0x80); /* 等待 */
|
||
}
|
||
}
|
||
|
||
int getbyte() {
|
||
int msr; // 软盘驱动器状态寄存器
|
||
int tmo; // 软盘驱动器状态寄存器的超时计数器
|
||
|
||
for (tmo = 0; tmo < 128; tmo++){
|
||
msr = io_in8(FDC_MSR);
|
||
if ((msr & 0xd0) == 0xd0){
|
||
return io_in8(FDC_DATA);
|
||
}
|
||
io_in8(0x80); /* 延时 */
|
||
}
|
||
return -1; /* 没读取到 */
|
||
}
|
||
|
||
void set_waiter(struct task_struct *t) {
|
||
while(waiter); // wait
|
||
waiter = t;
|
||
}
|
||
|
||
void reset(void) {
|
||
set_waiter(get_current());
|
||
io_out8(FDC_DOR, 0);
|
||
|
||
mtick = 0;
|
||
motor = 0;
|
||
|
||
io_out8(FDC_DRS, 0);
|
||
|
||
io_out8(FDC_DOR, 0x0c);
|
||
|
||
wait_floppy_interrupt();
|
||
sendbyte(CMD_SPECIFY);
|
||
sendbyte(0xdf); /* SRT = 3ms, HUT = 240ms */
|
||
sendbyte(0x02); /* HLT = 16ms, ND = 0 */
|
||
|
||
recalibrate();
|
||
|
||
dchange =
|
||
0; //清除“磁盘更改”状态(将dchange设置为false,让别的函数知道磁盘更改状态已经被清楚了)
|
||
}
|
||
void motoron(void) {
|
||
if (!motor) {
|
||
mtick = -1; /* 停止电机计时 */
|
||
io_out8(FDC_DOR, 0x1c);
|
||
for (int i = 0; i < 80000; i++)
|
||
;
|
||
motor = 1; //设置电机状态为true
|
||
}
|
||
}
|
||
|
||
/* 关闭电机 */
|
||
void motoroff(void) {
|
||
if (motor) {
|
||
mtick = 13500; /* 重新初始化电机计时器 */
|
||
}
|
||
}
|
||
|
||
/* 重新校准驱动器 */
|
||
void recalibrate() {
|
||
set_waiter(get_current());
|
||
/* 先启用电机 */
|
||
motoron();
|
||
|
||
/* 然后重新校准电机 */
|
||
sendbyte(CMD_RECAL);
|
||
sendbyte(0);
|
||
|
||
/* 等待软盘中断(也就是电机校准成功) */
|
||
wait_floppy_interrupt();
|
||
/* 关闭电机 */
|
||
motoroff();
|
||
}
|
||
|
||
void wait_floppy_interrupt() {
|
||
io_sti();
|
||
while(!floppy_int_count);
|
||
statsz = 0; // 清空状态
|
||
while ((statsz < 7) &&(io_in8(FDC_MSR) &(1<< 4))) {
|
||
status[statsz++] = getbyte(); // 获取数据
|
||
}
|
||
|
||
/* 获取中断状态 */
|
||
sendbyte(CMD_SENSEI);
|
||
sr0 = getbyte();
|
||
fdc_track = getbyte();
|
||
|
||
floppy_int_count = 0;
|
||
floppy_use = NULL;
|
||
return;
|
||
}
|
||
|
||
int seek(int track) {
|
||
if (fdc_track == track) /* 目前的磁道和需要seek的磁道一样吗 */
|
||
{
|
||
// 一样的话就不用seek了
|
||
return 1;
|
||
}
|
||
set_waiter(get_current());
|
||
/* 向软盘控制器发送SEEK命令 */
|
||
sendbyte(CMD_SEEK);
|
||
sendbyte(0);
|
||
sendbyte(track); /* 要seek到的磁道号 */
|
||
|
||
/* 发送完之后,软盘理应会送来一个中断 */
|
||
wait_floppy_interrupt(); // 所以我们需要等待软盘中断
|
||
|
||
for (int i = 0; i < 500; i++)
|
||
;
|
||
/* 检查一下成功了没有 */
|
||
if ((sr0 != 0x20) || (fdc_track != track))
|
||
return 0; // 没成功
|
||
else
|
||
return 1; // 成功了
|
||
}
|
||
|
||
void block2hts(int block, int* track, int* head, int* sector) {
|
||
*track = (block / 18) / 2;
|
||
*head = (block / 18) % 2;
|
||
*sector = block % 18 + 1;
|
||
}
|
||
|
||
void hts2block(int track, int head, int sector, int* block) {
|
||
*block = track * 18 * 2 + head * 18 + sector;
|
||
}
|
||
|
||
int fdc_rw(int block,
|
||
unsigned char* blockbuff,
|
||
int read,
|
||
unsigned long nosectors) {
|
||
set_waiter(get_current());
|
||
int head, track, sector, tries, copycount = 0;
|
||
unsigned char* p_tbaddr =
|
||
(char*)0x80000; // 512byte
|
||
// 缓冲区(大家可以放心,我们再page.c已经把这里设置为占用了)
|
||
unsigned char* p_blockbuff = blockbuff; // r/w的数据缓冲区
|
||
|
||
/* 获取block对应的ths */
|
||
block2hts(block, &track, &head, §or);
|
||
|
||
motoron();
|
||
|
||
if (!read && blockbuff) {
|
||
/* 从数据缓冲区复制数据到轨道缓冲区 */
|
||
for (copycount = 0; copycount < (nosectors * 512); copycount++) {
|
||
*p_tbaddr = *p_blockbuff;
|
||
p_blockbuff++;
|
||
p_tbaddr++;
|
||
}
|
||
}
|
||
|
||
for (tries = 0; tries < 3; tries++) {
|
||
/* 检查 */
|
||
if (io_in8(FDC_DIR) & 0x80) {
|
||
waiter = NULL;
|
||
dchange = 1;
|
||
seek(1); /* 清除磁盘更改 */
|
||
recalibrate();
|
||
motoroff();
|
||
return fdc_rw(block, blockbuff, read, nosectors);
|
||
}
|
||
waiter = NULL;
|
||
/* seek到track的位置*/
|
||
if (!seek(track)) {
|
||
motoroff();
|
||
waiter = NULL;
|
||
return 0;
|
||
}
|
||
set_waiter(get_current());
|
||
/* 传输速度(500K/s) */
|
||
io_out8(FDC_CCR, 0);
|
||
|
||
/* 发送命令 */
|
||
if (read) {
|
||
dma_xfer(2, tbaddr, nosectors * 512, 0);
|
||
sendbyte(CMD_READ);
|
||
} else {
|
||
dma_xfer(2, tbaddr, nosectors * 512, 1);
|
||
sendbyte(CMD_WRITE);
|
||
}
|
||
|
||
sendbyte(head << 2);
|
||
sendbyte(track);
|
||
sendbyte(head);
|
||
sendbyte(sector);
|
||
sendbyte(2); /* 每个扇区是512字节 */
|
||
sendbyte(geometry.spt);
|
||
|
||
if (geometry.spt == DG144_SPT)
|
||
sendbyte(DG144_GAP3RW);
|
||
else
|
||
sendbyte(DG168_GAP3RW);
|
||
sendbyte(0xff);
|
||
|
||
/* 等待中断...... */
|
||
/* 读写数据不需要中断状态 */
|
||
wait_floppy_interrupt();
|
||
|
||
if ((status[0] & 0xc0) == 0)
|
||
break; /* worked! outta here! */
|
||
waiter = NULL;
|
||
recalibrate(); /* az,报错了,再试一遍 */
|
||
}
|
||
|
||
/* 关闭电动机 */
|
||
motoroff();
|
||
|
||
if (read && blockbuff) {
|
||
/* 复制数据 */
|
||
p_blockbuff = blockbuff;
|
||
p_tbaddr = (char*)0x80000;
|
||
for (copycount = 0; copycount < (nosectors * 512); copycount++) {
|
||
*p_blockbuff = *p_tbaddr;
|
||
p_blockbuff++;
|
||
p_tbaddr++;
|
||
}
|
||
}
|
||
|
||
return (tries != 3);
|
||
}
|