驱动程序的作用在于隐藏硬件细节,向上层进程提供统一的接口。由于我们的进程通过收发消息来相互通信,那么驱动程序的接口自然也是消息了。所以只要我们定义了驱动程序可以接收什么消息,也就定义了驱动程序的接口。
我们先只定义一种消息:DEV_OPEN。我们过会儿通过FS任务向硬盘驱动程序发送一个DEV_OPEN消息。可是硬盘驱动程序收到这个消息之后干点什么呢?我们还是先干点简单工作:向硬盘驱动器发送一个IDENTIFY命令,这个命令可用来获取硬盘数。
task_hd( )是硬盘驱动的主循环,它跟我们之前的任务没什么两样。开头调用init_hd()做一些初始化工作,然后开始不停地处理消息。我们目前只接收DEV_OPEN消息,收到它之后将会调用hd_identify()来获取并打印部分硬盘参数。
init_hd()中所做的工作分两部分。它先是从物理地址0x475处获取系统内硬盘数量──这个地址是由BIOS指定的。然后它指定hd_handler()为硬盘中断处理程序,并且打开硬盘中断。
hd_identify(int drive)便是获取硬盘参数的函数了。用了一个函数hd_cmd_out()来进行实际的向硬盘驱动器发送命令的工作,因为今后我们还会用到它。当发送命令之后,我们用interrupt_wait()这一函数来等待中断的发生,而等待的方法是调用了一个接收消息的函数。向硬盘发送命令以后,硬盘不是实时返回数据的,硬盘执行完命令以后,会产生中断,所以驱动程序需要等待中断程序通知驱动程序继续执行。
发送接收消息 执行out命令后主动阻塞
task_fs进程<-------------------->task_hd硬盘驱动-------------------->硬盘外设
^ |
|唤醒 |
| 触发中断 |
硬盘中断处理程序<-----------------------|
PUBLIC void task_hd()
{
MESSAGE msg;
init_hd();
while (1) {
send_recv(RECEIVE, ANY, &msg);
int src = msg.source;
switch (msg.type) {
case DEV_OPEN:
hd_identify(0);
break;
default:
dump_msg("HD driver::unknown msg", &msg);
spin("FS::main_loop (invalid msg.type)");
break;
}
send_recv(SEND, src, &msg);
}
}
/*****************************************************************************
* init_hd
*****************************************************************************/
/**
* <Ring 1> Check hard drive, set IRQ handler, enable IRQ and initialize data
* structures.
*****************************************************************************/
PRIVATE void init_hd()
{
/* Get the number of drives from the BIOS data area */
u8 * pNrDrives = (u8*)(0x475);
printl("NrDrives:%d.\n", *pNrDrives);
assert(*pNrDrives);
put_irq_handler(AT_WINI_IRQ, hd_handler);
enable_irq(CASCADE_IRQ);
enable_irq(AT_WINI_IRQ);
}
/*****************************************************************************
* hd_identify
*****************************************************************************/
/**
* <Ring 1> Get the disk information.
*
* @param drive Drive Nr.
*****************************************************************************/
PRIVATE 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();
port_read(REG_DATA, hdbuf, SECTOR_SIZE);
print_identify_info((u16*)hdbuf);
}
/*****************************************************************************
* interrupt_wait
*****************************************************************************/
/**
* <Ring 1> Wait until a disk interrupt occurs.
*
*****************************************************************************/
PRIVATE void interrupt_wait()
{
MESSAGE msg;
send_recv(RECEIVE, INTERRUPT, &msg);
}
/*****************************************************************************
* hd_handler
*****************************************************************************/
/**
* <Ring 0> Interrupt handler.
*
* @param irq IRQ nr of the disk interrupt.
*****************************************************************************/
PUBLIC 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 = in_byte(REG_STATUS);
inform_int(TASK_HD);
}
我们新建立的文件系统进程其实就是个空壳,它什么都不做,只是向硬盘驱动程序发送一个DEV_OPEN消息。跟之前的所有进程一样,FS进程会在系统启动时开始运行,所以我们在启动操作系统之后很快硬盘驱动就会接收到DEV_OPEN消息,并且获取硬盘参数并进行一些打印工作。
/*****************************************************************************
* task_fs
*****************************************************************************/
/**
* <Ring 1> The main loop of TASK FS.
*
*****************************************************************************/
PUBLIC void task_fs()
{
printl("Task FS begins.\n");
/* open the device: hard disk */
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
send_recv(BOTH, TASK_HD, &driver_msg);
spin("FS");
}