⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 em86xx 完整启动程序,支持网络下载与串通下载
💻 C
📖 第 1 页 / 共 3 页
字号:
            }         }    } #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, &sector);    ++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, &regbase, &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, &regbase, &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 + -