Bool BlkDevLock(CBlkDev *bd) {//Make this task have exclusive access to BlkDev. BlkDevCheck(bd); while (bd->lock_fwding) bd = bd->lock_fwding; //If two blkdevs on same controller, use just one lock if (!Bt(&bd->locked_flags, BDlf_LOCKED) || bd->owning_task != Fs) { while (LBts(&bd->locked_flags, BDlf_LOCKED)) Yield; bd->owning_task = Fs; return TRUE; } else return FALSE; } Bool BlkDevUnlock(CBlkDev *bd, Bool reset=FALSE) {//Release exclusive lock on access to BlkDev. BlkDevCheck(bd); while (bd->lock_fwding) bd = bd->lock_fwding; //If two blkdevs on same controller, use just one lock if (Bt(&bd->locked_flags, BDlf_LOCKED) && bd->owning_task == Fs) { if (reset) bd->flags &= ~(BDF_INITIALIZED | BDF_INIT_IN_PROGRESS); bd->owning_task = NULL; LBtr(&bd->locked_flags, BDlf_LOCKED); Yield; //Prevent deadlock return TRUE; } else return FALSE; } Bool BlkDevInit(CBlkDev *bd) { CDirEntry de; U8 buf[STR_LEN]; CDrive *drive = Letter2Drive(bd->first_drive_let); Bool res = FALSE; if (!LBts(&bd->flags, BDf_INITIALIZED)) { bd->flags |= BDF_INIT_IN_PROGRESS; switch (bd->type) { case BDT_RAM: if (!bd->RAM_disk) { bd->RAM_disk = SysMAlloc((bd->max_blk + 1) << BLK_SIZE_BITS); bd->max_blk = MSize(bd->RAM_disk) >> BLK_SIZE_BITS - 1; } drive->fs_type = FSt_REDSEA; drive->size = bd->max_blk + 1 - bd->drv_offset; if (RedSeaValidate(bd->first_drive_let)) RedSeaInit(drive); else RedSeaFormat(bd->first_drive_let); res = TRUE; break; case BDT_ISO_FILE_READ: if (FileFind(bd->file_disk_name, &de, FUF_JUST_FILES)) { bd->max_blk = de.size >> BLK_SIZE_BITS - 1; try bd->file_disk = FOpen(bd->file_disk_name, "rc", bd->max_blk + 1); catch { if (Fs->except_ch == 'File') PrintErr("Not Contiguous. Move file to filename.ISO.C.\n"); Fs->catch_except = TRUE; } if (bd->file_disk) { drive->fs_type = FSt_REDSEA; drive->size = bd->max_blk + 1 - bd->drv_offset; if (RedSeaValidate(bd->first_drive_let)) { RedSeaInit(drive); res = TRUE; } else PrintErr("Not RedSea\n"); } } break; case BDT_ISO_FILE_WRITE: if (!bd->file_disk_name) { StrPrint(buf, "%C:/Drive%C.ISO.C", blkdev.boot_drive_let, bd->first_drive_let); bd->file_disk_name = SysStrNew(buf); } if (bd->max_blk < 7) bd->max_blk = 7; bd->file_disk = FOpen(bd->file_disk_name, "wc", bd->max_blk + 1); drive->fs_type = FSt_REDSEA; drive->size = bd->max_blk + 1 - bd->drv_offset; RedSeaFormat(bd->first_drive_let); CallExtStr("RedSeaISO9660", bd->file_disk_name, bd->first_drive_let); res = TRUE; break; case BDT_ATA: bd->max_reads = 128; bd->max_writes = 1; res = AHCIAtaInit(bd); break; case BDT_ATAPI: //0xFFFF*4 is too big for Terry's taste bd->max_reads = 0x800 * 4; //max of maybe a quarter of disk cache if (bd->max_reads > blkdev.cache_size / BLK_SIZE / 4) bd->max_reads = blkdev.cache_size / BLK_SIZE / 4 & ~3; if (bd->max_reads < 128) bd->max_reads = 128; bd->max_writes = 0xFFFF * 4; if (res = AHCIAtaInit(bd)) drive->size = bd->max_blk + 1; break; } if (res && bd->flags & BDF_READ_CACHE) DiskCacheInvalidate(drive); bd->flags &= ~BDF_INIT_IN_PROGRESS; } else res = TRUE; return res; } U0 BlkDevsRelease() {//When task dies, release all owned BlkDevs. I64 i; CBlkDev *bd; for (i = 0; i < BLKDEVS_NUM; i++) { bd = &blkdev.blkdevs[i]; if (bd->owning_task == Fs && bd->bd_signature == BD_SIGNATURE_VAL) BlkDevUnlock(bd, TRUE); } } CBlkDev *BlkDevNextFreeSlot(U8 first_drive_let, I64 type) {//Locate free slot for new BlkDev, like during Mount(). I64 i = 0; CBlkDev *res; if (Letter2BlkDevType(first_drive_let) != type) throw('BlkDev'); do { res = &blkdev.blkdevs[i]; if (res->bd_signature != BD_SIGNATURE_VAL) { MemSet(res, 0, sizeof(CBlkDev)); res->first_drive_let = first_drive_let; res->type = type; res->flags = BDF_READ_CACHE; res->blk_size = BLK_SIZE; res->max_blk = 0xEFFFFFFF; switch (type) { case BDT_RAM: res->flags &= ~BDF_READ_CACHE; break; case BDT_ISO_FILE_READ: res->flags |= BDF_READ_ONLY; break; case BDT_ATAPI: res->flags |= BDF_REMOVABLE|BDF_READ_ONLY; res->blk_size = DVD_BLK_SIZE; break; } return res; } } while (++i < BLKDEVS_NUM); throw('BlkDev'); return NULL; //never gets here } U0 BlkDevDel(CBlkDev *bd) {//Delete BlkDev DriveBlkDevDel(bd); FClose(bd->file_disk); Free(bd->file_disk_name); Free(bd->dev_id_record); MemSet(bd, 0, sizeof(CBlkDev)); } CBlkDev *BlkDevCheck(CBlkDev *bd, Bool except=TRUE) {//Check for valid BlkDev. Throw exception. if (!bd || bd->bd_signature != BD_SIGNATURE_VAL || !(BDT_NULL<bd->type < BDT_TYPES_NUM)) { if (except) throw('BlkDev'); else return NULL; } else return bd; } CBlkDev *Letter2BlkDev(U8 drv_let=0, Bool except=TRUE) {//Drive letter to BlkDev pointer. CDrive *drive; if (drive = Letter2Drive(drv_let, except)) return BlkDevCheck(drive->bd, except); else return NULL; } U0 BlkDevRep() { // Block Device Report. // blkdev.blkdevs[i]. I64 i; CBlkDev *b = blkdev.blkdevs; for (i = 0; i < BLKDEVS_NUM; i++) { if (b[i].bd_signature == BD_SIGNATURE_VAL) { "\nBlock Device #%d:\n", i; "\tBlock Device Type:\t%Z\n", b[i].type, "ST_BLKDEV_TYPES"; "\tFirst Drive Letter:\t%C\n", b[i].first_drive_let; if (b[i].ahci_port) { "\tAHCI Port number:\t%d\n", b[i].port_num; "\tAHCI Port address:\t0x%X\n", b[i].ahci_port; } if (b[i].RAM_disk) "\tRAM disk address:\t0x%X\n", b[i].RAM_disk; if (b[i].file_disk_name) "\tFile:\t\t\t\t%s\n", b[i].file_disk_name; "\tBlock Size:\t\t\t%d\n", b[i].blk_size; "\tDrive Max Block:\t0x%X\n", b[i].max_blk; } } "\n"; }