📄 ata.c
字号:
DEBUGF("ata_flush()\n"); delayed_write = false; ata_write_sectors(delayed_sector_num, 1, delayed_sector); }}static int check_registers(void){ if ( ATA_STATUS & STATUS_BSY ) return -1; ATA_NSECTOR = 0xa5; ATA_SECTOR = 0x5a; ATA_LCYL = 0xaa; ATA_HCYL = 0x55; if ((ATA_NSECTOR == 0xa5) && (ATA_SECTOR == 0x5a) && (ATA_LCYL == 0xaa) && (ATA_HCYL == 0x55)) return 0; return -2;}static int freeze_lock(void){ ATA_SELECT = ata_device; if (!wait_for_rdy()) return -1; ATA_COMMAND = CMD_SECURITY_FREEZE_LOCK; if (!wait_for_rdy()) return -2; return 0;}void ata_spindown(int seconds){ sleep_timeout = seconds * HZ;}#ifdef HAVE_ATA_POWER_OFFvoid ata_poweroff(bool enable){ if (enable) poweroff_timeout = 2*HZ; else poweroff_timeout = 0;}#endifbool ata_disk_is_active(void){ return !sleeping;}static int ata_perform_sleep(void){ int ret = 0; mutex_lock(&ata_mtx); ATA_SELECT = ata_device; if(!wait_for_rdy()) { DEBUGF("ata_perform_sleep() - not RDY\n"); mutex_unlock(&ata_mtx); return -1; } ATA_COMMAND = CMD_SLEEP; if (!wait_for_rdy()) { DEBUGF("ata_perform_sleep() - CMD failed\n"); ret = -2; } sleeping = true; mutex_unlock(&ata_mtx); return ret;}int ata_standby(int time){ int ret = 0; mutex_lock(&ata_mtx); ATA_SELECT = ata_device; if(!wait_for_rdy()) { DEBUGF("ata_standby() - not RDY\n"); mutex_unlock(&ata_mtx); return -1; } if(time) ATA_NSECTOR = ((time + 5) / 5) & 0xff; /* Round up to nearest 5 secs */ else ATA_NSECTOR = 0; /* Disable standby */ ATA_COMMAND = CMD_STANDBY; if (!wait_for_rdy()) { DEBUGF("ata_standby() - CMD failed\n"); ret = -2; } mutex_unlock(&ata_mtx); return ret;}int ata_sleep(void){ queue_post(&ata_queue, Q_SLEEP, NULL); return 0;}void ata_spin(void){ last_user_activity = current_tick;}static void ata_thread(void){ static long last_sleep = 0; struct event ev; while (1) { while ( queue_empty( &ata_queue ) ) { if ( !spinup && sleep_timeout && !sleeping && TIME_AFTER( current_tick, last_user_activity + sleep_timeout ) && TIME_AFTER( current_tick, last_disk_activity + sleep_timeout ) ) { ata_perform_sleep(); last_sleep = current_tick; }#ifdef HAVE_ATA_POWER_OFF if ( !spinup && sleeping && poweroff_timeout && !poweroff && TIME_AFTER( current_tick, last_sleep + poweroff_timeout )) { mutex_lock(&ata_mtx); ide_power_enable(false); mutex_unlock(&ata_mtx); poweroff = true; }#endif sleep(HZ/4); } queue_wait(&ata_queue, &ev); switch ( ev.id ) {#ifndef USB_NONE case SYS_USB_CONNECTED: if (poweroff) { mutex_lock(&ata_mtx); led(true); ata_power_on(); led(false); mutex_unlock(&ata_mtx); } /* Tell the USB thread that we are safe */ DEBUGF("ata_thread got SYS_USB_CONNECTED\n"); usb_acknowledge(SYS_USB_CONNECTED_ACK); /* Wait until the USB cable is extracted again */ usb_wait_for_disconnect(&ata_queue); break;#endif case Q_SLEEP: last_disk_activity = current_tick - sleep_timeout + (HZ/2); break; } }}/* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */int ata_hard_reset(void){ int ret; /* state HRR0 */ and_b(~0x02, &PADRH); /* assert _RESET */ sleep(1); /* > 25us */ /* state HRR1 */ or_b(0x02, &PADRH); /* negate _RESET */ sleep(1); /* > 2ms */ /* state HRR2 */ ATA_SELECT = ata_device; /* select the right device */ ret = wait_for_bsy(); /* Massage the return code so it is 0 on success and -1 on failure */ ret = ret?0:-1; return ret;}static int perform_soft_reset(void){ int ret; int retry_count; ATA_SELECT = SELECT_LBA | ata_device; ATA_CONTROL = CONTROL_nIEN|CONTROL_SRST; sleep(1); /* >= 5us */ ATA_CONTROL = CONTROL_nIEN; sleep(1); /* >2ms */ /* This little sucker can take up to 30 seconds */ retry_count = 8; do { ret = wait_for_rdy(); } while(!ret && retry_count--); /* Massage the return code so it is 0 on success and -1 on failure */ ret = ret?0:-1; return ret;}int ata_soft_reset(void){ int ret; mutex_lock(&ata_mtx); ret = perform_soft_reset(); mutex_unlock(&ata_mtx); return ret;}static int ata_power_on(void){ int rc; ide_power_enable(true); if( ata_hard_reset() ) return -1; rc = set_features(); if (rc) return rc * 10 - 2; if (set_multiple_mode(multisectors)) return -3; if (freeze_lock()) return -4; return 0;}static int master_slave_detect(void){ /* master? */ ATA_SELECT = 0; if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) { ata_device = 0; DEBUGF("Found master harddisk\n"); } else { /* slave? */ ATA_SELECT = SELECT_DEVICE1; if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) { ata_device = SELECT_DEVICE1; DEBUGF("Found slave harddisk\n"); } else return -1; } return 0;}static int io_address_detect(void){ /* now, use the HW mask instead of probing */ if (read_hw_mask() & ATA_ADDRESS_200) { ata_io_address = 0x200; /* For debug purposes only */ old_recorder = false; ata_control = ATA_CONTROL1; } else { ata_io_address = 0x300; /* For debug purposes only */ old_recorder = true; ata_control = ATA_CONTROL2; } return 0;}void ata_enable(bool on){ if(on) and_b(~0x80, &PADRL); /* enable ATA */ else or_b(0x80, &PADRL); /* disable ATA */ or_b(0x80, &PAIORL);}static int identify(void){ int i; ATA_SELECT = ata_device; if(!wait_for_rdy()) { DEBUGF("identify() - not RDY\n"); return -1; } ATA_COMMAND = CMD_IDENTIFY; if (!wait_for_start_of_transfer()) { DEBUGF("identify() - CMD failed\n"); return -2; } for (i=0; i<SECTOR_SIZE/2; i++) /* the IDENTIFY words are already swapped */ identify_info[i] = ATA_DATA; return 0;}static int set_multiple_mode(int sectors){ ATA_SELECT = ata_device; if(!wait_for_rdy()) { DEBUGF("set_multiple_mode() - not RDY\n"); return -1; } ATA_NSECTOR = sectors; ATA_COMMAND = CMD_SET_MULTIPLE_MODE; if (!wait_for_rdy()) { DEBUGF("set_multiple_mode() - CMD failed\n"); return -2; } return 0;}static int set_features(void){ struct { unsigned char id_word; unsigned char id_bit; unsigned char subcommand; unsigned char parameter; } features[] = { { 83, 3, 0x05, 1 }, /* power management: lowest power */ { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */ { 82, 6, 0xaa, 0 }, /* enable read look-ahead */ { 83, 14, 0x03, 0 }, /* force PIO mode */ { 0, 0, 0, 0 } /* <end of list> */ }; int i; int pio_mode = 2; /* Find out the highest supported PIO mode */ if(identify_info[64] & 2) pio_mode = 4; else if(identify_info[64] & 1) pio_mode = 3; /* Update the table */ features[3].parameter = 8 + pio_mode; ATA_SELECT = ata_device; if (!wait_for_rdy()) { DEBUGF("set_features() - not RDY\n"); return -1; } for (i=0; features[i].id_word; i++) { if (identify_info[features[i].id_word] & (1 << features[i].id_bit)) { ATA_FEATURE = features[i].subcommand; ATA_NSECTOR = features[i].parameter; ATA_COMMAND = CMD_SET_FEATURES; if (!wait_for_rdy()) { DEBUGF("set_features() - CMD failed\n"); return -10 - i; } if(ATA_ALT_STATUS & STATUS_ERR) { if(ATA_ERROR & ERROR_ABRT) { return -20 - i; } } } } return 0;}unsigned short* ata_get_identify(void){ return identify_info;}int ata_init(void){ int rc; bool coldstart = (PACR2 & 0x4000) != 0; mutex_init(&ata_mtx); led(false); /* Port A setup */ or_b(0x02, &PAIORH); /* output for ATA reset */ or_b(0x02, &PADRH); /* release ATA reset */ PACR2 &= 0xBFFF; /* GPIO function for PA7 (IDE enable) */ sleeping = false; ata_enable(true); if ( !initialized ) { if (!ide_powered()) /* somebody has switched it off */ { ide_power_enable(true); sleep(HZ); /* allow voltage to build up */ } if (coldstart) { /* Reset both master and slave, we don't yet know what's in */ /* this is safe because non-present devices don't report busy */ ata_device = 0; if (ata_hard_reset()) return -1; ata_device = SELECT_DEVICE1; if (ata_hard_reset()) return -2; } rc = master_slave_detect(); if (rc) return -10 + rc; rc = io_address_detect(); if (rc) return -20 + rc; /* symptom fix: else check_registers() below may fail */ if (coldstart && !wait_for_bsy()) { return -29; } rc = check_registers(); if (rc) return -30 + rc; rc = freeze_lock(); if (rc) return -40 + rc; rc = identify(); if (rc) return -50 + rc; multisectors = identify_info[47] & 0xff; DEBUGF("ata: %d sectors per ata request\n",multisectors); rc = set_features(); if (rc) return -60 + rc; queue_init(&ata_queue); last_disk_activity = current_tick; create_thread(ata_thread, ata_stack, sizeof(ata_stack), ata_thread_name); initialized = true; } rc = set_multiple_mode(multisectors); if (rc) return -70 + rc; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -