nkeynes@31: /** nkeynes@39: * $Id: ide.c,v 1.6 2005-12-26 10:47:34 nkeynes Exp $ nkeynes@2: * nkeynes@31: * IDE interface implementation nkeynes@31: * nkeynes@31: * Copyright (c) 2005 Nathan Keynes. nkeynes@31: * nkeynes@31: * This program is free software; you can redistribute it and/or modify nkeynes@31: * it under the terms of the GNU General Public License as published by nkeynes@31: * the Free Software Foundation; either version 2 of the License, or nkeynes@31: * (at your option) any later version. nkeynes@31: * nkeynes@31: * This program is distributed in the hope that it will be useful, nkeynes@31: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@31: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@31: * GNU General Public License for more details. nkeynes@2: */ nkeynes@35: nkeynes@35: #define MODULE ide_module nkeynes@35: nkeynes@2: #include nkeynes@35: #include "dream.h" nkeynes@39: #include "gdrom/ide.h" nkeynes@2: nkeynes@2: #define MAX_WRITE_BUF 4096; nkeynes@2: nkeynes@15: void ide_init( void ); nkeynes@15: void ide_init( void ); nkeynes@15: nkeynes@15: struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL, nkeynes@23: NULL, NULL, NULL }; nkeynes@15: nkeynes@2: struct ide_registers idereg; nkeynes@2: nkeynes@2: static char command_buffer[12]; nkeynes@2: nkeynes@2: /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */ nkeynes@2: char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, nkeynes@2: 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, nkeynes@2: 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, nkeynes@2: 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 }; nkeynes@2: nkeynes@2: nkeynes@2: void set_write_buffer( char *buf, int len ) nkeynes@2: { nkeynes@2: idereg.status |= IDE_ST_DATA; nkeynes@2: idereg.data = buf; nkeynes@2: idereg.datalen = len; nkeynes@2: idereg.writeptr = (uint16_t *)buf; nkeynes@2: idereg.readptr = NULL; nkeynes@2: } nkeynes@2: nkeynes@2: void set_read_buffer( char *buf, int len ) nkeynes@2: { nkeynes@2: idereg.status |= IDE_ST_DATA; nkeynes@2: idereg.data = buf; nkeynes@2: idereg.datalen = len; nkeynes@2: idereg.readptr = (uint16_t *)buf; nkeynes@2: idereg.writeptr = NULL; nkeynes@2: idereg.lba1 = len&0xFF; nkeynes@2: idereg.lba2 = len>>8; nkeynes@2: } nkeynes@2: nkeynes@2: void ide_clear_interrupt( void ) nkeynes@2: { nkeynes@2: /* TODO */ nkeynes@2: } nkeynes@2: nkeynes@15: void ide_init( void ) nkeynes@15: { nkeynes@15: nkeynes@15: } nkeynes@15: nkeynes@2: void ide_reset( void ) nkeynes@2: { nkeynes@2: ide_clear_interrupt(); nkeynes@2: idereg.error = 0x01; nkeynes@2: idereg.count = 0x01; nkeynes@2: idereg.lba0 = 0x21; nkeynes@2: idereg.lba1 = 0x14; nkeynes@2: idereg.lba2 = 0xeb; nkeynes@2: idereg.feature = 0; /* Indeterminate really */ nkeynes@2: idereg.status = 0x00; nkeynes@2: idereg.device = 0x00; nkeynes@2: idereg.disc = IDE_DISC_GDROM | IDE_DISC_READY; nkeynes@2: } nkeynes@2: nkeynes@2: uint16_t ide_read_data_pio( void ) { nkeynes@2: if( idereg.readptr == NULL ) nkeynes@2: return 0xFFFF; nkeynes@2: uint16_t rv = *idereg.readptr++; nkeynes@2: idereg.datalen-=2; nkeynes@2: if( idereg.datalen <=0 ) { nkeynes@2: idereg.readptr = NULL; nkeynes@2: idereg.status &= ~IDE_ST_DATA; nkeynes@2: } nkeynes@2: return rv; nkeynes@2: } nkeynes@2: nkeynes@2: void ide_write_data_pio( uint16_t val ) { nkeynes@2: if( idereg.writeptr == NULL ) nkeynes@2: return; nkeynes@2: *idereg.writeptr++ = val; nkeynes@2: idereg.datalen-=2; nkeynes@2: if( idereg.datalen <= 0 ) { nkeynes@2: idereg.writeptr = NULL; nkeynes@2: idereg.status &= ~IDE_ST_DATA; nkeynes@2: ide_write_buffer( idereg.data ); nkeynes@2: } nkeynes@2: } nkeynes@2: nkeynes@2: void ide_write_control( uint8_t val ) { nkeynes@2: /* TODO: In theory we can cause a soft-reset here, but the DC doesn't nkeynes@2: * appear to support it. nkeynes@2: */ nkeynes@2: } nkeynes@2: nkeynes@2: void ide_write_command( uint8_t val ) { nkeynes@2: idereg.command = val; nkeynes@2: switch( val ) { nkeynes@39: case IDE_CMD_RESET_DEVICE: nkeynes@39: ide_reset(); nkeynes@39: break; nkeynes@39: case IDE_CMD_PACKET: nkeynes@39: set_write_buffer(command_buffer,12); nkeynes@39: break; nkeynes@39: case IDE_CMD_SET_FEATURE: nkeynes@39: switch( idereg.feature ) { nkeynes@39: default: nkeynes@39: WARN( "IDE: unimplemented feature: %02X", idereg.feature ); nkeynes@39: } nkeynes@39: break; nkeynes@39: default: nkeynes@39: WARN( "IDE: Unimplemented command: %02X", val ); nkeynes@2: } nkeynes@2: idereg.status |= IDE_ST_READY | IDE_ST_SERV; nkeynes@2: } nkeynes@2: nkeynes@2: void ide_write_buffer( char *data ) { nkeynes@2: uint16_t length; nkeynes@2: switch( idereg.command ) { nkeynes@2: case IDE_CMD_PACKET: nkeynes@2: /* Okay we have the packet in the command buffer */ nkeynes@2: WARN( "ATAPI: Received Packet command: %02X", data[0] ); nkeynes@2: nkeynes@2: switch( command_buffer[0] ) { nkeynes@2: case PKT_CMD_IDENTIFY: nkeynes@2: /* NB: Bios sets data[4] = 0x08, no idea what this is for; nkeynes@2: * different values here appear to have no effect. nkeynes@2: */ nkeynes@2: length = *((uint16_t*)(data+2)); nkeynes@2: if( length > sizeof(gdrom_ident) ) nkeynes@2: length = sizeof(gdrom_ident); nkeynes@2: set_read_buffer(gdrom_ident, length); nkeynes@2: break; nkeynes@2: } nkeynes@2: break; nkeynes@2: } nkeynes@2: }