📄 ide.c
字号:
} } } #if IDE_VERBOSE else uart_puts("\n");#endif return 0;}#define IDE_WAIT_TIMEOUT 1000int ide_wait_stat(int mask, int waitmask, int btimeout){ int status; int timeout = IDE_WAIT_TIMEOUT; do { status = ide_inb(IDE_STATUS_REG); if (btimeout) { if (timeout-- == 0) {#if IDE_VERBOSE uart_puts("timeout ");#endif return 1; } em86xx_msleep(1); } } while ((status & mask) != waitmask); return 0;}int ide_select_drive(int drive, int ready){ unsigned short select = g_ideinfo[drive].select.all; unsigned int status; ide_outb(select, IDE_SELECT_REG); if (ide_wait_stat(IDESTAT_BUSY, 0, 1)) return 1; if ((ide_inb(IDE_SELECT_REG) & 0xff) != select) return 1; if (!ready) return 0; status = ide_inb(IDE_STATUS_REG); return (status & IDESTAT_READY) ? 0 : 1;}// wcount = word count (16 bits)void ide_input_data(unsigned short *buf, unsigned int wcount){ unsigned short *ptr = (unsigned short *) buf; // read data if (ptr == NULL) { while (wcount-- > 0) ide_inw(IDE_DATA_REG); } else { while (wcount-- > 0) *ptr++ = ide_inw(IDE_DATA_REG); }}void ide_output_data(unsigned short *buf, unsigned int wcount){ unsigned short *ptr = (unsigned short *) buf; // write data if (ptr == NULL) { while (wcount-- > 0) ide_outw(0, IDE_DATA_REG); } else { while (wcount-- > 0) ide_outw(*ptr++, IDE_DATA_REG); }}void ide_fixstring(unsigned char *s, const int bytecount, const int byteswap){ unsigned char *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */ if (byteswap) { /* convert from big-endian to host unsigned char order */ for (p = end ; p != s;) { unsigned short *pp = (unsigned short *) (p -= 2); *pp = ntohs(*pp); } } /* strip leading blanks */ while (s != end && *s == ' ') ++s; /* compress internal blanks and strip trailing blanks */ while (s != end && *s) { if (*s++ != ' ' || (s != end && *s && *s != ' ')) *p++ = *(s-1); } /* wipe out trailing garbage */ while (p != end) *p++ = '\0';}//// IDE Identify//static int ide_identify_cmd(int cmd, int drive, ide_id_t *pid);ide_info_t *ide_identify(int drive){ ide_info_t *pideinfo = g_ideinfo + drive; ide_id_t *pid = &pideinfo->id; pideinfo->type = IDE_NONE; if (ide_identify_cmd(ATACMD_IDENTIFY, drive, pid) == 0) { // probe for ATA device pideinfo->type = IDE_ATA; pideinfo->cyls = pid->cyls; pideinfo->heads = pid->heads; pideinfo->sectors = pid->sectors; // C/H/S = 16383/16/63 : LBA if (pid->cyls == 16383 && pid->heads == 16 && pid->sectors == 63) { pideinfo->lba = 1; pideinfo->nsectors = pid->lba_capacity; pideinfo->select.b.lba = 1; } else { pideinfo->lba = 0; pideinfo->nsectors = pid->cyls * pid->heads * pid->sectors; pideinfo->select.b.lba = 0; } pideinfo->cap_dma = (pideinfo->id.capability & 0x0100) ? 1 : 0; pideinfo->cap_udma = (pideinfo->id.field_valid & 0x04) ? 1 : 0; pideinfo->size = pideinfo->nsectors >> 11; } else { // probe for ATAPI device // disable dma & overlap ide_outb(0, IDE_FEATURE_REG); if (ide_identify_cmd(ATACMD_PIDENTIFY, drive, pid) == 0) { pideinfo->type = IDE_ATAPI; } } return pideinfo;}int ide_identify_cmd(int cmd, int drive, ide_id_t *pid){ if (ide_command(cmd, drive, 0, 0, 0, 0, 0, pid, SECTOR_SIZE) == 0) { ide_fixstring(pid->model_num, sizeof(pid->model_num), 1); ide_fixstring(pid->firmware_rev, sizeof(pid->firmware_rev), 1); ide_fixstring(pid->serial_num, sizeof(pid->serial_num), 1); return 0; } else return 1;}//// Other commands//int ide_set_drive_speed(int drive, int speed){ return ide_command(ATACMD_SETFEATURES, drive, SETFEATURES_TRANSFER, 0, 0, 0, speed, NULL, 0);}//// IDE read/write//static int ide_chs_rw(int read, int dma, int drive, unsigned int block, unsigned char *buf, int nsector);static int ide_lbs_28_rw(int read, int dma, int drive, unsigned int block, unsigned char *buf, int nsector);int ide_rw_sector(int read, int dma, int drive, int cyl, int head, int sector, unsigned char *buf){ return ide_command(read ? (dma ? ATACMD_READDMA : ATACMD_READ) : (dma ? ATACMD_WRITEDMA : ATACMD_WRITE), drive, 0, cyl, head, sector, 1, buf, SECTOR_SIZE);}#define SECTOR_CHUNKS 8int ide_rw_block(int read, int dma, int drive, int block, unsigned char *buf, int nsector){ ide_info_t *pideinfo = g_ideinfo + drive; int nsector_transfer; if (pideinfo->type == IDE_NONE) return 1; while (nsector > 0) { nsector_transfer = (nsector >= SECTOR_CHUNKS) ? SECTOR_CHUNKS : nsector; if (pideinfo->lba) { if (ide_lbs_28_rw(read, dma, drive, block, buf, nsector_transfer)) return 1; } else { if (ide_chs_rw(read, dma, drive, block, buf, nsector_transfer)) return 1; } block += nsector_transfer; nsector -= nsector_transfer; buf += SECTOR_SIZE * nsector_transfer; } return 0;}int ide_chs_rw(int read, int dma, int drive, unsigned int block, unsigned char *buf, int nsector){ ide_info_t *pideinfo = g_ideinfo + drive; unsigned int track, sector, head, cyl; unsigned_divide(block, pideinfo->sectors, &track, §or); ++sector; unsigned_divide(track, pideinfo->heads, &cyl, &head); return ide_command(read ? (dma ? ATACMD_READDMA : ATACMD_READ) : (dma ? ATACMD_WRITEDMA : ATACMD_WRITE), drive, 0, cyl, head, sector, nsector, buf, SECTOR_SIZE * nsector);}int ide_lbs_28_rw(int read, int dma, int drive, unsigned int block, unsigned char *buf, int nsector){ int head, cyl, sector; sector = block & 0xff; cyl = (block >> 8) & 0xffff; head = (block >> 24) & 0xff; return ide_command(read ? (dma ? ATACMD_READDMA : ATACMD_READ) : (dma ? ATACMD_WRITEDMA : ATACMD_WRITE), drive, 0, cyl, head, sector, nsector, buf, SECTOR_SIZE * nsector);}//// IDE DMA transfer//int ide_rw_dma_block(int read, int drive, int block, unsigned char *buf, int nsector, unsigned int *timerus){ int port, irq; unsigned int regbase; int buflen = SECTOR_SIZE * nsector; ide_info_t *pideinfo = g_ideinfo + drive; unsigned int timer_start, timer_end; if (!pideinfo->use_udma && !pideinfo->use_dma) { uart_puts("WARNING : DMA is not supported\n"); return 1; }#ifdef CONFIG_ENABLE_IDE_BM __raw_writel(0x04, REG_BASE_HOST + IDECTRL_bmic); __raw_writel(0x00000000, REG_BASE_HOST + IDECTRL_idesrc); __raw_writel(0x8400, REG_BASE_HOST + IDECTRL_pri_idectl);#endif em86xx_clean_cache_data_region((unsigned int) buf, (unsigned int) buf + buflen); // Use DMA mode transfer // Transfer starts when the IDE device is ready and asserts DMARQ signal high // setup switchbox#ifdef CONFIG_ENABLE_IDE_BM port = em86xx_mbus_alloc_dma(SBOX_IDEDVD, read, ®base, &irq); em86xx_mbus_setup_dma(regbase, (unsigned int) buf, buflen); // setup IDE DMA pointer and length __raw_writel(((unsigned long) buflen), REG_BASE_HOST + IDECTRL_ide_dmalen);#else port = em86xx_mbus_alloc_dma(SBOX_IDEFLASH, read, ®base, &irq); // setup PB automode registers __raw_writel(0, REG_BASE_HOST + PB_automode_start_address); __raw_writel(0x00140000 | ((read ? 1 : 0) << 16) | (buflen >> 1), REG_BASE_HOST + PB_automode_control); em86xx_mbus_setup_dma(regbase, (unsigned int) buf, buflen);#endif timer_start = __raw_readl(REG_BASE_system_block + SYS_xtal_in_cnt); // send READ command if (pideinfo->lba) { if (ide_lbs_28_rw(read, 1, drive, block, NULL, nsector)) return 1; } else { if (ide_chs_rw(read, 1, drive, block, NULL, nsector)) return 1; }#ifdef CONFIG_ENABLE_IDE_BM // start bus master IDE __raw_writel(0x05 | (read ? 0x08 : 0x00), REG_BASE_HOST + IDECTRL_bmic); // wait for interrupt and clear interrupt // Use IRQ_IDECTRL_IDE interrupt for both of PIO and DMA. em86xx_irq_wait(IRQ_IDECTRL_IDE); while((__raw_readl(REG_BASE_HOST + IDECTRL_bmis) & 0x4) == 0) ; __raw_writel(__raw_readl(REG_BASE_HOST + IDECTRL_bmis), REG_BASE_HOST + IDECTRL_bmis);#else // wait for interrupt and clear interrupt // waiting for DMA transfer ends em86xx_mbus_wait(regbase); em86xx_irq_wait(IRQ_IDE);#endif if(timerus) { timer_end = __raw_readl(REG_BASE_system_block + SYS_xtal_in_cnt); *timerus = (timer_end > timer_start ? (timer_end-timer_start) : ((0xffffffff-timer_start)+timer_end+1)) / 27; } ide_inb(IDE_STATUS_REG);#ifdef CONFIG_ENABLE_IDE_BM // Stop bus mastering __raw_writel(0x04, REG_BASE_HOST + IDECTRL_bmic);#endif // cleanup em86xx_mbus_free_dma(port); if (read) em86xx_flush_cache_data_region((unsigned int) buf, (unsigned int) buf + buflen); return 0;}//// partition table translation//#define MSDOS_LABEL_MAGIC1 0x55#define MSDOS_LABEL_MAGIC2 0xAAstruct partition { unsigned char boot_ind; /* 0x80 - active */ unsigned char head; /* starting head */ unsigned char sector; /* starting sector */ unsigned char cyl; /* starting cylinder */ unsigned char sys_ind; /* What partition type */ unsigned char end_head; /* end head */ unsigned char end_sector; /* end sector */ unsigned char end_cyl; /* end cylinder */ unsigned int start_sect; /* starting sector counting from 0 */ unsigned int nr_sects; /* nr of sectors in partition */} __attribute__((packed));static int msdos_magic_present(unsigned char *p){ return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);}static void part_to_partinfo(struct partition *part, ide_partition_t *partinfo){ partinfo->active = part->boot_ind & 0x80 ? 1 : 0; partinfo->type = part->sys_ind; partinfo->start.cylinder = ((part->sector & 0xc0) << 2) + part->cyl; partinfo->start.head = part->head; partinfo->start.sector = part->sector & 0x3f; partinfo->end.cylinder = ((part->end_sector & 0xc0) << 2) + part->end_cyl; partinfo->end.head = part->end_head; partinfo->end.sector = part->end_sector & 0x3f; partinfo->start_sector = part->start_sect; partinfo->nr_sects = part->nr_sects;}// return last partition number + 1int ide_read_partition(int drive, ide_partition_t *ret_partinfo, int showlist){ int i, npart = 0; unsigned char buf[SECTOR_SIZE]; struct partition *part; ide_partition_t partinfo; if (g_ideinfo[drive].type == IDE_ATAPI) return -1; if (ide_rw_block(1, 0, drive, 0, buf, 1)) { uart_puts("Can't read partition table\n"); return 0; } if (!msdos_magic_present(buf + 510)) { uart_puts("Invalid partition table\n"); return 0; } part = (struct partition *) (buf + 0x1be); if (showlist) uart_puts("# : A TYPE [ CYL / HEAD / SEC - CYL / HEAD / SEC ] (START, #SECT, SIZE)\n"); for (i = 0; i < 4; ++i) { if (part[i].nr_sects > 0) { part_to_partinfo(&part[i], &partinfo); if (ret_partinfo) { memcpy(&ret_partinfo[i], &partinfo, sizeof(ide_partition_t)); ret_partinfo[i].valid = 1; } npart = i + 1; if (showlist) { uart_printf("%d : %c %02x [ %4d / %4d / %3d - %4d / %4d / %3d ] (%d, %d = %dMB)\n", i, partinfo.active ? 'A' : ' ', partinfo.type, partinfo.start.cylinder, partinfo.start.head, partinfo.start.sector, partinfo.end.cylinder, partinfo.end.head, partinfo.end.sector, partinfo.start_sector, partinfo.nr_sects, partinfo.nr_sects >> 11); } } else { if (ret_partinfo) ret_partinfo[i].valid = 0; } } return npart;}int ide_rw_block_partition(int read, int dma, int drive, int partition, int block, unsigned char *buf, int nsector){ if (partition < 0 || partition >= g_ideinfo[drive].npart || !g_ideinfo[drive].part[partition].valid) return 1; if (dma) return ide_rw_dma_block(read, drive, g_ideinfo[drive].part[partition].start_sector + block, buf, nsector,NULL); else return ide_rw_block(read, 0, drive, g_ideinfo[drive].part[partition].start_sector + block, buf, nsector);}//// kernel image or filesystem in IDE device//int ide_probe_image(int drive, int *ppart, void *pinfo) { int i; int type; for (i = 0; i < g_ideinfo[drive].npart; ++i) { if (g_ideinfo[drive].part[i].valid && (type = ide_check_image(drive, i, 0, pinfo)) != IMAGE_TYPE_NONE) { *ppart = i; return type; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -