/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 by Alan Korr * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include "ata.h" #include "kernel.h" #include "thread.h" #include "led.h" #include "sh7034.h" #include "system.h" #include "debug.h" #include "panic.h" #include "usb.h" #include "power.h" #include "string.h" #include "hwcompat.h" #include "adc.h" /* use file for an MMC-based system, FIXME in makefile */ #ifdef HAVE_MMC #define SECTOR_SIZE 512 #define Q_SLEEP 0 /* for compatibility */ bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ int ata_spinup_time = 0; static int sleep_timeout = 5*HZ; char ata_device = 0; /* device 0 (master) or 1 (slave) */ int ata_io_address = 0; /* 0x300 or 0x200, only valid on recorder */ static unsigned short identify_info[SECTOR_SIZE]; static struct mutex ata_mtx; static bool sleeping = true; static char ata_stack[DEFAULT_STACK_SIZE]; static const char ata_thread_name[] = "ata"; static struct event_queue ata_queue; static bool initialized = false; static bool delayed_write = false; static unsigned char delayed_sector[SECTOR_SIZE]; static int delayed_sector_num; static long last_user_activity = -1; long last_disk_activity = -1; int ata_read_sectors(unsigned long start, int incount, void* inbuf) { int ret = 0; mutex_lock(&ata_mtx); last_disk_activity = current_tick; led(true); sleeping = false; /* ToDo: action */ (void)start; (void)incount; (void)inbuf; led(false); mutex_unlock(&ata_mtx); /* only flush if reading went ok */ if ( (ret == 0) && delayed_write ) ata_flush(); return ret; } int ata_write_sectors(unsigned long start, int count, const void* buf) { int ret = 0; if (start == 0) panicf("Writing on sector 0\n"); mutex_lock(&ata_mtx); sleeping = false; last_disk_activity = current_tick; led(true); /* ToDo: action */ (void)start; (void)count; (void)buf; led(false); mutex_unlock(&ata_mtx); /* only flush if writing went ok */ if ( (ret == 0) && delayed_write ) ata_flush(); return ret; } extern void ata_delayed_write(unsigned long sector, const void* buf) { memcpy(delayed_sector, buf, SECTOR_SIZE); delayed_sector_num = sector; delayed_write = true; } extern void ata_flush(void) { if ( delayed_write ) { DEBUGF("ata_flush()\n"); delayed_write = false; ata_write_sectors(delayed_sector_num, 1, delayed_sector); } } void ata_spindown(int seconds) { sleep_timeout = seconds * HZ; } bool ata_disk_is_active(void) { return !sleeping; } static int ata_perform_sleep(void) { int ret = 0; mutex_lock(&ata_mtx); /* ToDo: is there an equivalent? */ sleeping = true; mutex_unlock(&ata_mtx); return ret; } int ata_standby(int time) { int ret = 0; mutex_lock(&ata_mtx); /* ToDo: is there an equivalent? */ (void)time; 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 ( 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; } sleep(HZ/4); } queue_wait(&ata_queue, &ev); switch ( ev.id ) { #ifndef USB_NONE case SYS_USB_CONNECTED: /* 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 = 0; return ret; } int ata_soft_reset(void) { int ret = 0; return ret; } void ata_enable(bool on) { PBCR1 &= ~0x0CC0; /* PB13 and TxD1 become GPIOs, if not modified below */ if (on) { /* serial setup */ PBCR1 |= 0x0880; /* as SCK1, TxD1 */ } else { PBDR |= 0x2000; /* drive PB13 high */ PBIOR |= 0x2000; /* output PB13 */ PBIOR &= ~0x0800; /* high impedance for TxD1 GPIO */ PADR |= 0x0680; /* set all the selects+reset high (=inactive) */ PADR &= ~0x0080; /* assert reset */ sleep(1); PADR |= 0x0080; /* de-assert reset */ } } unsigned short* ata_get_identify(void) { return identify_info; } int ata_init(void) { int rc = 0; mutex_init(&ata_mtx); led(false); /* Port setup */ PADR |= 0x0680; /* set all the selects + reset high (=inactive) */ PAIOR |= 0x1680; /* make outputs for them and the PA12 clock gate */ if(adc_read(ADC_MMC_SWITCH) < 0x200) { /* MMC inserted */ PADR &= ~0x1000; /* clear PA12 */ PADR &= ~0x0200; /* chip select external flash */ } else { /* no MMC, use internal memory */ PADR |= 0x1000; /* set PA12 */ PADR &= ~0x0400; /* chip select internal flash */ } sleeping = false; ata_enable(true); if ( !initialized ) { queue_init(&ata_queue); last_disk_activity = current_tick; create_thread(ata_thread, ata_stack, sizeof(ata_stack), ata_thread_name); initialized = true; } return rc; } #endif /* #ifdef HAVE_MMC */