📄 hd.c
字号:
base = pointer-offset;
byteoff = offset*DEF_SECTORSIZE;
pItem = bufsAdd(pList, base, 0);
if(!pItem) return DEVICE_MAKEERR(DEVERR_MEMORY);
ret = bufsPrepare(pItem, dr_cmd==DR_READ ? BLP_READ : BLP_WRITE);
if(ret!=ERR_SUCCESS) return ret;
if(dr_cmd==DR_READ)
l = bufsRead(pItem, byteoff, buffer, min(l0, pList->item_size-byteoff));
else
l = bufsWrite(pItem, byteoff, buffer, min(l0, pList->item_size-byteoff));
l1 += l; l0 -= l; buffer += l;
pointer += l/DEF_SECTORSIZE;
if(len) *len = l1/DEF_SECTORSIZE;
}
return 0;
}
static long doSeek(HDEVICE hDevice, SEEKPACKET *sp, _u64 *final)
{
_s32 block, delta;
HDDEVICE *pDev = GetDeviceExtraMem(hDevice);
// convert to sector-based
block = (_s32)(sp->original/DEF_SECTORSIZE);
delta = (_s32)(sp->delta/DEF_SECTORSIZE);
switch(sp->mode)
{
case SEEK_SET:
if(delta<0 || (_u32)delta>=pDev->length) return DEVICE_MAKEERR(DEVERR_NOTEXIST);
*final = (_u64)(_u32)delta*DEF_SECTORSIZE;
break;
case SEEK_CUR:
if(block+delta<0 || (_u32)(block+delta)>=pDev->length)
return DEVICE_MAKEERR(DEVERR_NOTEXIST);
*final = (_u64)(_u32)(block+delta)*DEF_SECTORSIZE;
break;
case SEEK_END:
if(delta>0 || (_u32)(-delta)>=pDev->length)
return DEVICE_MAKEERR(DEVERR_NOTEXIST);
*final = (_u64)(_u32)((_s32)pDev->length-1+delta)*DEF_SECTORSIZE;
break;
}
return 0;
}
static long doInitialize(HDEVICE hDevice, HDDEVICE *params)
{
BUFFERLIST *pBufferList;
HDDEVICE *pDev = GetDeviceExtraMem(hDevice);
// save hd-device information
if(!pDev || !params) return DEVICE_MAKEERR(DEVERR_PARAMS);
memcpy(pDev, params, sizeof(HDDEVICE));
// create buffer-list and request-queue
pBufferList = bufsCreate(sizeof(HDEVICE), hd_buffers_proc, (_u32)hDevice);
if(!pBufferList) return DEVICE_MAKEERR(DEVERR_INTERNAL);
SetDeviceBufferList(hDevice, pBufferList);
// load magic information for partitions
if(pDev->partition!=0)
{
char buf[512];
int r = hdd_read(pDev->drive, pDev->base, buf, 1);
if(r!=0) return DEVICE_MAKEERR(DEVERR_INTERNAL|r);
memcpy(pDev->magic, buf, 16);
}
return 0;
}
static long doIdentify(HDEVICE hDevice, char *buf, _u32 len, _u32 *t_len)
{
if(!buf || len<4) return DEVICE_MAKEERR(DEVERR_PARAMS);
*(_u32*)buf = ((HDDEVICE*)GetDeviceExtraMem(hDevice))->type;
if(len>4)
{
len-=4;
if(len>16) len = 16;
memcpy(buf+4, ((HDDEVICE*)GetDeviceExtraMem(hDevice))->magic, len);
}
if(t_len) *t_len = len+4;
return 0;
}
static long __syscall ioctrl(HDEVICE hDevice, _u32 cmd, void* in_buf, _u32 in_len, void* out_buf, _u32 out_len, _u32* trans_len)
{
switch(cmd)
{
case DEV_IOCTRL_INITIALIZE: return doInitialize(hDevice, (HDDEVICE*)*(_u32*)in_buf);
case DEV_IOCTRL_READ: return doTransfer(hDevice, (DDTPACKET*)in_buf, trans_len, DR_READ);
case DEV_IOCTRL_WRITE: return doTransfer(hDevice, (DDTPACKET*)in_buf, trans_len, DR_WRITE);
case DEV_IOCTRL_SEEK: return doSeek(hDevice, (SEEKPACKET*)in_buf, (_u64*)out_buf);
case DEV_IOCTRL_IDENTIFY: return doIdentify(hDevice, (char*)out_buf, out_len, trans_len);
}
return DEVICE_MAKEERR(DEVERR_BADCMD);
}
// Installation routines
static int hdd_identify(int pri_sec, int drive, void *buf)
{
int drv = ((drive<<4)&0x10)|0xa0;
_outb(pri_sec+HDPA_HEAD, drv);
if((wait_ide(pri_sec)&0x50)!=0x50) return 0;
_outb(pri_sec+HDPA_HEAD, drv);
_outb(pri_sec+HDPA_CMD, 0xec);
if((wait_ide(pri_sec)&0x58)!=0x58) return 0;
_insw(pri_sec, buf, 256);
return 1;
}
static void swapb(char *buf, int len)
{
int i, b;
for(i=0; i<len; i+=2)
{ b = buf[i]; buf[i] = buf[i+1]; buf[i+1] = (char)b; }
}
static void detect_hdd(int pri_sec)
{
char buf[512];
int i;
_outb(pri_sec+HDPA_CMD, 0x08); // reset device
if(wait_ide(pri_sec)&0x80) return;
kprintf("Detecting %s IDE controler...", pri_sec==IDE_PRIMARY?"primary":"secondary");
for(i=0; i<2; i++)
{
if(hdd_identify(pri_sec, i, buf))
{
int id = (pri_sec==IDE_PRIMARY?0:2)+i;
_hdd_drives[id].port_base = pri_sec;
_hdd_drives[id].drive_id = i;
_hdd_drives[id].n_cylinders = *(_u16*)(buf+0x02);
_hdd_drives[id].n_heads = *(_u16*)(buf+0x06);
_hdd_drives[id].n_sectors = *(_u16*)(buf+0x0c);
_hdd_drives[id].capbilities = *(_u16*)(buf+0x62);
_hdd_drives[id].n_multimax = *(_u16*)(buf+0x5e);
_hdd_drives[id].n_dwtrans = *(_u16*)(buf+0x60);
_hdd_drives[id].n_LBAsectors = _hdd_drives[id].capbilities&HDC_LBA ? *(_u32*)(buf+0x78)
: chs_to_lba(id, _hdd_drives[id].n_cylinders-1,
_hdd_drives[id].n_heads-1,
_hdd_drives[id].n_sectors);
strncpy(_hdd_drives[id].serial_number, buf+0x14, 20);
_hdd_drives[id].serial_number[20]=0;
strncpy(_hdd_drives[id].model_number, buf+0x36, 40);
_hdd_drives[id].model_number[40]=0;
swapb(_hdd_drives[id].model_number, 40);
TrimRight(_hdd_drives[id].serial_number, ' ');
TrimRight(_hdd_drives[id].model_number, ' ');
kprintf("\r%s %s drive found: %s (%s, %s, %s)\n",
pri_sec==IDE_PRIMARY?"Primary":"Secondary",
i==0?"master":"slave",
_hdd_drives[id].model_number,
_hdd_drives[id].n_LBAsectors?"LBA":"CHS",
_hdd_drives[id].capbilities&HDC_DMA?"DMA":"PIO",
_hdd_drives[id].n_dwtrans?"D":"W");
}
}
kprintf("\r \r");
}
static int register_drive(int id, int partition, int type, _u32 base, _u32 len)
{
char name[8];
HDDEVICE hddev;
if(partition) ksprintf(name, "hd%c%d", id+'a', partition);
else ksprintf(name, "hd%c", id+'a');
memset(&hddev, 0, sizeof(hddev));
hddev.drive = id;
hddev.partition = partition;
hddev.type = type;
hddev.base = base;
hddev.length = len;
if(!RegisterDevice(_this_driver, DEV_TYPE_BLOCK, DEV_SEEKING, DEF_SECTORSIZE, name, ioctrl,
sizeof(HDDEVICE), (_u32)&hddev))
{ kprintf("%s: device registering failed\n", name); return 0; }
return 1;
}
static int register_extension(int id, _u32 base, _u32 len, int part)
{
int r, cnt = 0;
char buf[512], name[8];
_u32 p, next = base;
while(next)
{
ksprintf(name, "hd%c%d", id+'a', part+cnt);
r = hdd_read(id, next, buf, 1);
if(r!=0)
{ kprintf("%s: sector 0 read error: %04X\n", name, r); break; }
if(*(_u16*)(buf+0x1fe)!=0xaa55)
{ kprintf("%s: bad extended partition chain\n", name); break; }
register_drive(id, part+cnt, (_u8)buf[0x1be +4], *(_u32*)(buf+0x1be +8), *(_u32*)(buf+0x1be +12));
cnt++;
p = buf[0x1be +20] ? base+*(_u32*)(buf+0x1be +24) : 0;
if(p && p<=next)
{ kprintf("%s: logic-lock found\n", name); break; }
next = p;
}
return cnt;
}
static void register_hdd(void)
{
int i, j, r;
char name[8], buf[512], ch;
for(i=0; i<4; i++)
if(DRIVE_VALID(_hdd_drives[i]))
{
ksprintf(name, "hd%c", i+'a');
if(!register_drive(i, 0, 0, 0, _hdd_drives[i].n_LBAsectors)) continue;
r = hdd_read(i, 0, buf, 1);
if(r!=0)
{ kprintf("%s: sector 0 read error: %04X\n", name, r); continue; }
if(*(_u16*)(buf+0x1fe)!=0xaa55)
{ kprintf("%s: bad MBR\n", name); continue; }
r = 5;
for(j=0; j<4; j++)
{
ch = buf[0x1be +j*16+4];
if(ch==0x0f || ch==0x05)
r+=register_extension(i, *(_u32*)(buf+0x1be +j*16+8), *(_u32*)(buf+0x1be +j*16+12), r);
else if(ch)
register_drive(i, j+1, ch, *(_u32*)(buf+0x1be +j*16+8), *(_u32*)(buf+0x1be +j*16+12));
}
}
}
static long OnLoad(HDRIVER hDriver)
{
_this_driver = hDriver;
memset(_hdd_drives, 0, sizeof(DRIVE)*4);
rqInitialize(&_hdd_requestqueue, 0, 0, sizeof(DEVREQUEST), NULL, hd_queue_proc, 0);
return 0;
}
static long OnUnload(void)
{
return 0;
}
void onHD(void)
{
REQUEST *r;
SysLock();
r = rqGetPendingRequest(&_hdd_requestqueue);
if(r)
{
DEVREQUEST *dr = rqGetRequestExtraMem(r);
int id, port, c;
KASSERT(dr, "onHD: null dr");
KASSERT(r->status==RS_PENDING, "onHD: request not pending");
id = ((HDDEVICE*)GetDeviceExtraMem(dr->device))->drive;
port = _hdd_drives[id].port_base;
c = wait_ide(port);
if(c==0x58)
{
if(_hdd_drives[id].n_dwtrans) // use dword transfer
{
if((dr->flags&DR_CMDMASK)==DR_READ)
_insl(port, dr->buffer, dr->blocks*DEF_SECTORSIZE/4);
else
_outsl(port, dr->buffer, dr->blocks*DEF_SECTORSIZE/4);
}
else
{
if((dr->flags&DR_CMDMASK)==DR_READ)
_insw(port, dr->buffer, dr->blocks*DEF_SECTORSIZE/2);
else
_outsw(port, dr->buffer, dr->blocks*DEF_SECTORSIZE/2);
}
dr->errcode = 0;
}
else
{
dr->errcode = HDE_TIMEOUT|c;
}
r->status = RS_COMPLETE;
rqMoveNext(&_hdd_requestqueue);
SignalBottomHalfProc(0xe, 1);
}
else KTRACE("onHD: no request\n");
SysUnlock();
}
static void doHDBH(int todo)
{
if(SysIsItemLocked(LOCK_TASK)) return;
SignalBottomHalfProc(0xe, 0);
SysLock();
rqNext(&_hdd_requestqueue);
SysUnlock();
SignalReschedule();
}
static long OnInstallDevices(void)
{
// Detect IDE drives
detect_hdd(IDE_PRIMARY);
detect_hdd(IDE_SECONDARY);
// Register logical drives
register_hdd();
// Install hdd interrupt
RegisterBottomHalfProc(0xe, doHDBH);
SetIRQ(0xe, (_u32)irq_hd);
return 0;
}
long __syscall drvDefaultIDE(_u32 cmd, _u32 param1, _u32 param2)
{
switch(cmd)
{
case DRV_SVC_LOAD: return OnLoad((HDRIVER)param1);
case DRV_SVC_UNLOAD: return OnUnload();
case DRV_SVC_INSTALLDEVICES:
return OnInstallDevices();
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -