673 lines
19 KiB
C
673 lines
19 KiB
C
/// zcr copy whole file from Orange's and the file was modified.
|
|
|
|
/*************************************************************************//**
|
|
*****************************************************************************
|
|
* @file hd.c
|
|
* @brief Hard disk (winchester) driver.
|
|
* The `device nr' in this file means minor device nr.
|
|
* @author Forrest Y. Yu
|
|
* @date 2005~2008
|
|
*****************************************************************************
|
|
*****************************************************************************/
|
|
|
|
#include "type.h"
|
|
#include "const.h"
|
|
#include "protect.h"
|
|
#include "string.h"
|
|
#include "proc.h"
|
|
#include "global.h"
|
|
#include "proto.h"
|
|
#include "fs_const.h"
|
|
#include "hd.h"
|
|
#include "fs.h"
|
|
#include "fs_misc.h"
|
|
#include "x86.h"
|
|
#include "stdio.h"
|
|
#include "assert.h"
|
|
|
|
struct part_ent PARTITION_ENTRY;
|
|
|
|
//added by xw, 18/8/28
|
|
static HDQueue hdque;
|
|
static volatile int hd_int_waiting_flag;
|
|
static u8 hd_status;
|
|
static u8 hdbuf[SECTOR_SIZE * 2];
|
|
//static struct hd_info hd_info[1];
|
|
struct hd_info hd_info[1]; //modified by mingxuan 2020-10-27
|
|
|
|
static void init_hd_queue(HDQueue *hdq);
|
|
static void in_hd_queue(HDQueue *hdq, RWInfo *p);
|
|
static int out_hd_queue(HDQueue *hdq, RWInfo **p);
|
|
static void hd_rdwt_real(RWInfo *p);
|
|
|
|
static void get_part_table(int drive, int sect_nr, struct part_ent *entry);
|
|
static void partition(int device, int style);
|
|
static void print_hdinfo(struct hd_info *hdi);
|
|
static void hd_identify(int drive);
|
|
static void print_identify_info(u16 *hdinfo);
|
|
static void hd_cmd_out(struct hd_cmd *cmd);
|
|
|
|
static void inform_int();
|
|
static void interrupt_wait();
|
|
static void hd_handler(int irq);
|
|
static int waitfor(int mask, int val, int timeout);
|
|
//~xw
|
|
|
|
#define DRV_OF_DEV(dev) (dev <= MAX_PRIM ? \
|
|
dev / NR_PRIM_PER_DRIVE : \
|
|
(dev - MINOR_hd1a) / NR_SUB_PER_DRIVE)
|
|
|
|
/*****************************************************************************
|
|
* init_hd
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Check hard drive, set IRQ handler, enable IRQ and initialize data
|
|
* structures.
|
|
*****************************************************************************/
|
|
void init_hd()
|
|
{
|
|
int i;
|
|
|
|
put_irq_handler(AT_WINI_IRQ, hd_handler);
|
|
enable_irq(CASCADE_IRQ);
|
|
enable_irq(AT_WINI_IRQ);
|
|
|
|
for (i = 0; i < (sizeof(hd_info) / sizeof(hd_info[0])); i++)
|
|
memset(&hd_info[i], 0, sizeof(hd_info[0]));
|
|
hd_info[0].open_cnt = 0;
|
|
|
|
init_hd_queue(&hdque);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* hd_open
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> This routine handles DEV_OPEN message. It identify the drive
|
|
* of the given device and read the partition table of the drive if it
|
|
* has not been read.
|
|
*
|
|
* @param device The device to be opened.
|
|
*****************************************************************************/
|
|
// void hd_open(int device) //no need for int device, mingxuan
|
|
void hd_open(int drive) //modified by mingxuan 2020-10-27
|
|
{
|
|
kprintf("Read hd information... ");
|
|
|
|
/* Get the number of drives from the BIOS data area */
|
|
// u8 * pNrDrives = (u8*)(0x475);
|
|
hd_identify(drive);
|
|
|
|
if (hd_info[drive].open_cnt++ == 0) {
|
|
partition(drive * (NR_PART_PER_DRIVE + 1), P_PRIMARY);
|
|
print_hdinfo(&hd_info[drive]);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* hd_close
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> This routine handles DEV_CLOSE message.
|
|
*
|
|
* @param device The device to be opened.
|
|
*****************************************************************************/
|
|
void hd_close(int device)
|
|
{
|
|
int drive = DRV_OF_DEV(device);
|
|
|
|
hd_info[drive].open_cnt--;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* hd_rdwt
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> This routine handles DEV_READ and DEV_WRITE message.
|
|
*
|
|
* @param p Message ptr.
|
|
*****************************************************************************/
|
|
void hd_rdwt(MESSAGE * p)
|
|
{
|
|
int drive = DRV_OF_DEV(p->DEVICE);
|
|
|
|
u64 pos = p->POSITION;
|
|
|
|
//We only allow to R/W from a SECTOR boundary:
|
|
|
|
u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); // pos / SECTOR_SIZE
|
|
int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE;
|
|
sect_nr += p->DEVICE < MAX_PRIM ?
|
|
hd_info[drive].primary[p->DEVICE].base :
|
|
hd_info[drive].logical[logidx].base;
|
|
|
|
struct hd_cmd cmd;
|
|
cmd.features = 0;
|
|
cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
|
cmd.lba_low = sect_nr & 0xFF;
|
|
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
|
|
cmd.lba_high = (sect_nr >> 16) & 0xFF;
|
|
cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF);
|
|
cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE;
|
|
hd_cmd_out(&cmd);
|
|
|
|
int bytes_left = p->CNT;
|
|
void * la = (void*)va2la(p->PROC_NR, p->BUF);
|
|
|
|
while (bytes_left) {
|
|
int bytes = min(SECTOR_SIZE, bytes_left);
|
|
if (p->type == DEV_READ) {
|
|
interrupt_wait();
|
|
insw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
memcpy(la, hdbuf, bytes);
|
|
}
|
|
else {
|
|
if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT))
|
|
("hd writing error.");
|
|
|
|
memcpy(hdbuf, la, bytes);
|
|
outsw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
interrupt_wait();
|
|
}
|
|
bytes_left -= SECTOR_SIZE;
|
|
la += SECTOR_SIZE;
|
|
}
|
|
}
|
|
|
|
//added by xw, 18/8/26
|
|
void hd_service()
|
|
{
|
|
RWInfo *rwinfo;
|
|
|
|
while(1)
|
|
{
|
|
//the hd queue is not empty when out_hd_queue return 1.
|
|
while(out_hd_queue(&hdque, &rwinfo))
|
|
{
|
|
hd_rdwt_real(rwinfo);
|
|
rwinfo->proc->task.stat = READY;
|
|
}
|
|
yield();
|
|
}
|
|
|
|
}
|
|
|
|
static void hd_rdwt_real(RWInfo *p)
|
|
{
|
|
int drive = DRV_OF_DEV(p->msg->DEVICE);
|
|
|
|
u64 pos = p->msg->POSITION;
|
|
|
|
//We only allow to R/W from a SECTOR boundary:
|
|
|
|
u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); // pos / SECTOR_SIZE
|
|
int logidx = (p->msg->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE;
|
|
sect_nr += p->msg->DEVICE < MAX_PRIM ?
|
|
hd_info[drive].primary[p->msg->DEVICE].base :
|
|
hd_info[drive].logical[logidx].base;
|
|
|
|
struct hd_cmd cmd;
|
|
cmd.features = 0;
|
|
cmd.count = (p->msg->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
|
cmd.lba_low = sect_nr & 0xFF;
|
|
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
|
|
cmd.lba_high = (sect_nr >> 16) & 0xFF;
|
|
cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF);
|
|
cmd.command = (p->msg->type == DEV_READ) ? ATA_READ : ATA_WRITE;
|
|
hd_cmd_out(&cmd);
|
|
|
|
int bytes_left = p->msg->CNT;
|
|
void *la = p->kbuf; //attention here!
|
|
|
|
while (bytes_left) {
|
|
int bytes = min(SECTOR_SIZE, bytes_left);
|
|
if (p->msg->type == DEV_READ) {
|
|
interrupt_wait();
|
|
insw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
memcpy(la, hdbuf, bytes);
|
|
}
|
|
else {
|
|
if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT))
|
|
panic("hd writing error.");
|
|
|
|
memcpy(hdbuf, la, bytes);
|
|
outsw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
interrupt_wait();
|
|
}
|
|
bytes_left -= SECTOR_SIZE;
|
|
la += SECTOR_SIZE;
|
|
}
|
|
}
|
|
|
|
void hd_rdwt_sched(MESSAGE *p)
|
|
{
|
|
RWInfo rwinfo;
|
|
struct memfree hdque_buf;
|
|
int size = p->CNT;
|
|
void *buffer;
|
|
|
|
buffer = (void*)K_PHY2LIN(sys_kmalloc(size));
|
|
rwinfo.msg = p;
|
|
rwinfo.kbuf = buffer;
|
|
rwinfo.proc = p_proc_current;
|
|
|
|
if (p->type == DEV_READ) {
|
|
in_hd_queue(&hdque, &rwinfo);
|
|
p_proc_current->task.channel = &hdque;
|
|
p_proc_current->task.stat = SLEEPING;
|
|
sched();
|
|
memcpy(p->BUF, buffer, p->CNT);
|
|
} else {
|
|
memcpy(buffer, p->BUF, p->CNT);
|
|
in_hd_queue(&hdque, &rwinfo);
|
|
p_proc_current->task.channel = &hdque;
|
|
p_proc_current->task.stat = SLEEPING;
|
|
sched();
|
|
}
|
|
|
|
hdque_buf.addr = K_LIN2PHY((u32)buffer);
|
|
hdque_buf.size = size;
|
|
sys_free(&hdque_buf);
|
|
}
|
|
|
|
void init_hd_queue(HDQueue *hdq)
|
|
{
|
|
hdq->front = hdq->rear = NULL;
|
|
}
|
|
|
|
static void in_hd_queue(HDQueue *hdq, RWInfo *p)
|
|
{
|
|
p->next = NULL;
|
|
if(hdq->rear == NULL) { //put in the first node
|
|
hdq->front = hdq->rear = p;
|
|
} else {
|
|
hdq->rear->next = p;
|
|
hdq->rear = p;
|
|
}
|
|
}
|
|
|
|
static int out_hd_queue(HDQueue *hdq, RWInfo **p)
|
|
{
|
|
if (hdq->rear == NULL)
|
|
return 0; //empty
|
|
|
|
*p = hdq->front;
|
|
if (hdq->front == hdq->rear) { //put out the last node
|
|
hdq->front = hdq->rear = NULL;
|
|
} else {
|
|
hdq->front = hdq->front->next;
|
|
}
|
|
return 1; //not empty
|
|
}
|
|
//~xw
|
|
|
|
/*****************************************************************************
|
|
* hd_ioctl
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> This routine handles the DEV_IOCTL message.
|
|
*
|
|
* @param p Ptr to the MESSAGE.
|
|
*****************************************************************************/
|
|
void hd_ioctl(MESSAGE * p)
|
|
{
|
|
int device = p->DEVICE;
|
|
int drive = DRV_OF_DEV(device);
|
|
|
|
struct hd_info * hdi = &hd_info[drive];
|
|
|
|
if (p->REQUEST == DIOCTL_GET_GEO) {
|
|
void * dst = va2la(p->PROC_NR, p->BUF);
|
|
void * src = va2la(proc2pid(p_proc_current),
|
|
device < MAX_PRIM ?
|
|
&hdi->primary[device] :
|
|
&hdi->logical[(device - MINOR_hd1a) %
|
|
NR_SUB_PER_DRIVE]);
|
|
|
|
memcpy(dst, src, sizeof(struct part_info));
|
|
}
|
|
else {
|
|
// assert(0);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* get_part_table
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Get a partition table of a drive.
|
|
*
|
|
* @param drive Drive nr (0 for the 1st disk, 1 for the 2nd, ...)n
|
|
* @param sect_nr The sector at which the partition table is located.
|
|
* @param entry Ptr to part_ent struct.
|
|
*****************************************************************************/
|
|
static void get_part_table(int drive, int sect_nr, struct part_ent * entry)
|
|
{
|
|
struct hd_cmd cmd;
|
|
cmd.features = 0;
|
|
cmd.count = 1;
|
|
cmd.lba_low = sect_nr & 0xFF;
|
|
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
|
|
cmd.lba_high = (sect_nr >> 16) & 0xFF;
|
|
cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/
|
|
drive,
|
|
(sect_nr >> 24) & 0xF);
|
|
cmd.command = ATA_READ;
|
|
hd_cmd_out(&cmd);
|
|
interrupt_wait();
|
|
|
|
insw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
memcpy(entry,
|
|
hdbuf + PARTITION_TABLE_OFFSET,
|
|
sizeof(struct part_ent) * NR_PART_PER_DRIVE);
|
|
}
|
|
|
|
// added by mingxuan 2020-10-27
|
|
static void get_fs_flags(int drive, int sect_nr, struct fs_flags * fs_flags_buf)
|
|
{
|
|
struct hd_cmd cmd;
|
|
cmd.features = 0;
|
|
cmd.count = 1;
|
|
cmd.lba_low = sect_nr & 0xFF;
|
|
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
|
|
cmd.lba_high = (sect_nr >> 16) & 0xFF;
|
|
cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/
|
|
drive,
|
|
(sect_nr >> 24) & 0xF);
|
|
cmd.command = ATA_READ;
|
|
hd_cmd_out(&cmd);
|
|
interrupt_wait();
|
|
|
|
insw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
memcpy(fs_flags_buf,
|
|
hdbuf,
|
|
sizeof(struct fs_flags));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* partition
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> This routine is called when a device is opened. It reads the
|
|
* partition table(s) and fills the hd_info struct.
|
|
*
|
|
* @param device Device nr.
|
|
* @param style P_PRIMARY or P_EXTENDED.
|
|
*****************************************************************************/
|
|
static void partition(int device, int style)
|
|
{
|
|
int i;
|
|
int drive = DRV_OF_DEV(device);
|
|
struct hd_info * hdi = &hd_info[drive];
|
|
|
|
struct part_ent part_tbl[NR_SUB_PER_DRIVE];
|
|
|
|
if (style == P_PRIMARY) {
|
|
get_part_table(drive, drive, part_tbl);
|
|
|
|
int nr_prim_parts = 0;
|
|
for (i = 0; i < NR_PART_PER_DRIVE; i++) { /* 0~3 */
|
|
if (part_tbl[i].sys_id == NO_PART)
|
|
continue;
|
|
|
|
nr_prim_parts++;
|
|
int dev_nr = i + 1; /* 1~4 */
|
|
hdi->primary[dev_nr].base = part_tbl[i].start_sect;
|
|
hdi->primary[dev_nr].size = part_tbl[i].nr_sects;
|
|
|
|
// added by mingxuan 2020-10-27
|
|
struct fs_flags fs_flags_buf;
|
|
get_fs_flags(drive, hdi->primary[dev_nr].base+1, &fs_flags_buf); //hdi->primary[dev_nr].base + 1 beacause of orange and fat32 is in 2nd sector, mingxuan
|
|
if(fs_flags_buf.orange_flag == 0x11) // Orange's Magic
|
|
hdi->primary[dev_nr].fs_type = ORANGE_TYPE;
|
|
else if(fs_flags_buf.fat32_flag1 == 0x534f4453 && fs_flags_buf.fat32_flag2 == 0x302e35) // FAT32 flags
|
|
hdi->primary[dev_nr].fs_type = FAT32_TYPE;
|
|
// added end, mingxuan 2020-10-27
|
|
|
|
if (part_tbl[i].sys_id == EXT_PART) /* extended */
|
|
partition(device + dev_nr, P_EXTENDED);
|
|
}
|
|
}
|
|
else if (style == P_EXTENDED) {
|
|
int j = device % NR_PRIM_PER_DRIVE; /* 1~4 */
|
|
int ext_start_sect = hdi->primary[j].base;
|
|
int s = ext_start_sect;
|
|
int nr_1st_sub = (j - 1) * NR_SUB_PER_PART; /* 0/16/32/48 */
|
|
|
|
for (i = 0; i < NR_SUB_PER_PART; i++) {
|
|
int dev_nr = nr_1st_sub + i;/* 0~15/16~31/32~47/48~63 */
|
|
|
|
get_part_table(drive, s, part_tbl);
|
|
|
|
hdi->logical[dev_nr].base = s + part_tbl[0].start_sect;
|
|
hdi->logical[dev_nr].size = part_tbl[0].nr_sects;
|
|
|
|
// added by mingxuan 2020-10-29
|
|
struct fs_flags fs_flags_buf;
|
|
get_fs_flags(drive, hdi->logical[dev_nr].base+1, &fs_flags_buf); //hdi->primary[dev_nr].base + 1 beacause of orange and fat32 is in 2nd sector, mingxuan
|
|
if(fs_flags_buf.orange_flag == 0x11) // Orange's Magic
|
|
hdi->logical[dev_nr].fs_type = ORANGE_TYPE;
|
|
else if(fs_flags_buf.fat32_flag1 == 0x534f4453 && fs_flags_buf.fat32_flag2 == 0x302e35) // FAT32 flags
|
|
hdi->logical[dev_nr].fs_type = FAT32_TYPE;
|
|
// added end, mingxuan 2020-10-29
|
|
|
|
s = ext_start_sect + part_tbl[1].start_sect;
|
|
|
|
/* no more logical partitions
|
|
in this extended partition */
|
|
if (part_tbl[1].sys_id == NO_PART)
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// assert(0);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* print_hdinfo
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Print disk info.
|
|
*
|
|
* @param hdi Ptr to struct hd_info.
|
|
*****************************************************************************/
|
|
static void print_hdinfo(struct hd_info * hdi)
|
|
{
|
|
int i;
|
|
for (i = 0; i < NR_PART_PER_DRIVE + 1; i++) {
|
|
if(i == 0) {
|
|
kprintf(" ");
|
|
}
|
|
else {
|
|
kprintf(" ");
|
|
}
|
|
kprintf("PART_%d: base %d, size: %d (in sector)\n",
|
|
i, hdi->primary[i].base, hdi->primary[i].size);
|
|
}
|
|
for (i = 0; i < NR_SUB_PER_DRIVE; i++) {
|
|
if (hdi->logical[i].size == 0)
|
|
continue;
|
|
kprintf(" %d: base %d, size %d (in sector)\n",
|
|
i, hdi->logical[i].base, hdi->logical[i].size);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* hd_identify
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Get the disk information.
|
|
*
|
|
* @param drive Drive Nr.
|
|
*****************************************************************************/
|
|
static void hd_identify(int drive)
|
|
{
|
|
struct hd_cmd cmd;
|
|
cmd.device = MAKE_DEVICE_REG(0, drive, 0);
|
|
cmd.command = ATA_IDENTIFY;
|
|
hd_cmd_out(&cmd);
|
|
interrupt_wait();
|
|
insw(REG_DATA, hdbuf, SECTOR_SIZE);
|
|
|
|
print_identify_info((u16*)hdbuf);
|
|
|
|
u16* hdinfo = (u16*)hdbuf;
|
|
|
|
hd_info[drive].primary[0].base = 0;
|
|
/* Total Nr of User Addressable Sectors */
|
|
hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60];
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* print_identify_info
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Print the hdinfo retrieved via ATA_IDENTIFY command.
|
|
*
|
|
* @param hdinfo The buffer read from the disk i/o port.
|
|
*****************************************************************************/
|
|
static void print_identify_info(u16* hdinfo)
|
|
{
|
|
int i, k;
|
|
char s[64];
|
|
|
|
struct iden_info_ascii {
|
|
int idx;
|
|
int len;
|
|
char * desc;
|
|
} iinfo[] = {{10, 20, "HD SN"}, /* Serial number in ASCII */
|
|
{27, 40, "HD Model"} /* Model number in ASCII */ };
|
|
|
|
for (k = 0; k < sizeof(iinfo)/sizeof(iinfo[0]); k++) {
|
|
char * p = (char*)&hdinfo[iinfo[k].idx];
|
|
for (i = 0; i < iinfo[k].len/2; i++) {
|
|
s[i*2+1] = *p++;
|
|
s[i*2] = *p++;
|
|
}
|
|
s[i*2] = 0;
|
|
kprintf("%s: %s\n", iinfo[k].desc, s);
|
|
}
|
|
|
|
int capabilities = hdinfo[49];
|
|
kprintf("LBA supported:%s ", capabilities & 0x0200 ? "YES" : "NO");
|
|
|
|
int cmd_set_supported = hdinfo[83];
|
|
kprintf("LBA48 supported:%s ", cmd_set_supported & 0x0400 ? "YES" : "NO");
|
|
|
|
int sectors = ((int)hdinfo[61] << 16) + hdinfo[60];
|
|
kprintf("HD size:%dMB\n", sectors * 512 / 1000000);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* hd_cmd_out
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Output a command to HD controller.
|
|
*
|
|
* @param cmd The command struct ptr.
|
|
*****************************************************************************/
|
|
static void hd_cmd_out(struct hd_cmd* cmd)
|
|
{
|
|
/**
|
|
* For all commands, the host must first check if BSY=1,
|
|
* and should proceed no further unless and until BSY=0
|
|
*/
|
|
if (!waitfor(STATUS_BSY, 0, HD_TIMEOUT))
|
|
panic("hd error.");
|
|
|
|
/* Activate the Interrupt Enable (nIEN) bit */
|
|
outb(REG_DEV_CTRL, 0);
|
|
/* Load required parameters in the Command Block Registers */
|
|
outb(REG_FEATURES, cmd->features);
|
|
outb(REG_NSECTOR, cmd->count);
|
|
outb(REG_LBA_LOW, cmd->lba_low);
|
|
outb(REG_LBA_MID, cmd->lba_mid);
|
|
outb(REG_LBA_HIGH, cmd->lba_high);
|
|
outb(REG_DEVICE, cmd->device);
|
|
/* Write the command code to the Command Register */
|
|
outb(REG_CMD, cmd->command);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* interrupt_wait
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Wait until a disk interrupt occurs.
|
|
*
|
|
*****************************************************************************/
|
|
static void interrupt_wait()
|
|
{
|
|
while(hd_int_waiting_flag) {
|
|
|
|
}
|
|
hd_int_waiting_flag = 1;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* waitfor
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 1> Wait for a certain status.
|
|
*
|
|
* @param mask Status mask.
|
|
* @param val Required status.
|
|
* @param timeout Timeout in milliseconds.
|
|
*
|
|
* @return One if sucess, zero if timeout.
|
|
*****************************************************************************/
|
|
static int waitfor(int mask, int val, int timeout)
|
|
{
|
|
int t = sys_get_ticks();
|
|
|
|
while(((sys_get_ticks() - t) * 1000 / HZ) < timeout){
|
|
if ((inb(REG_STATUS) & mask) == val)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* hd_handler
|
|
*****************************************************************************/
|
|
/**
|
|
* <Ring 0> Interrupt handler.
|
|
*
|
|
* @param irq IRQ nr of the disk interrupt.
|
|
*****************************************************************************/
|
|
static void hd_handler(int irq)
|
|
{
|
|
/*
|
|
* Interrupts are cleared when the host
|
|
* - reads the Status Register,
|
|
* - issues a reset, or
|
|
* - writes to the Command Register.
|
|
*/
|
|
hd_status = inb(REG_STATUS);
|
|
inform_int();
|
|
|
|
/* There is two stages - in kernel intializing or in process running.
|
|
* Some operation shouldn't be valid in kernel intializing stage.
|
|
* added by xw, 18/6/1
|
|
*/
|
|
if(kernel_initial == 1){
|
|
return;
|
|
}
|
|
|
|
//some operation only for process
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* inform_int
|
|
*****************************************************************************/
|
|
static void inform_int()
|
|
{
|
|
hd_int_waiting_flag = 0;
|
|
return;
|
|
}
|