2 * $Id: ide.c,v 1.8 2006-03-22 14:29:02 nkeynes Exp $
4 * IDE interface implementation
6 * Copyright (c) 2005 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #define MODULE ide_module
24 #include "gdrom/ide.h"
25 #include "gdrom/gdrom.h"
27 #define MAX_WRITE_BUF 4096;
29 void ide_init( void );
30 void ide_init( void );
32 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
35 struct ide_registers idereg;
37 static unsigned char command_buffer[12];
39 /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */
40 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
41 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
42 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
43 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
46 gdrom_disc_t gdrom_disc = NULL;
48 static void ide_set_write_buffer( unsigned char *buf, int len )
50 idereg.status |= IDE_ST_DATA;
53 idereg.writeptr = (uint16_t *)buf;
54 idereg.readptr = NULL;
57 static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
59 idereg.status |= IDE_ST_DATA;
62 idereg.readptr = (uint16_t *)buf;
63 idereg.writeptr = NULL;
64 idereg.lba1 = len&0xFF;
66 idereg.blocksize = idereg.blockleft = blocksize;
69 static void ide_raise_interrupt( void )
71 if( idereg.intrq_pending == 0 ) {
72 idereg.intrq_pending = 1;
73 if( IS_IDE_IRQ_ENABLED() )
74 asic_event( EVENT_IDE );
78 static void ide_clear_interrupt( void )
80 if( idereg.intrq_pending != 0 ) {
81 idereg.intrq_pending = 0;
82 if( IS_IDE_IRQ_ENABLED() )
83 asic_clear_event( EVENT_IDE );
87 static void ide_set_error( int error_code )
90 idereg.error = error_code;
98 void ide_reset( void )
100 ide_clear_interrupt();
103 idereg.lba0 = /* 0x21; */ 0x81;
106 idereg.feature = 0; /* Indeterminate really */
107 idereg.status = 0x00;
108 idereg.device = 0x00;
109 idereg.disc = (gdrom_disc == NULL ? IDE_DISC_NONE : (IDE_DISC_CDROM|IDE_DISC_READY));
112 uint8_t ide_read_status( void )
114 if( (idereg.status & IDE_ST_BUSY) == 0 )
115 ide_clear_interrupt();
116 return idereg.status;
119 uint16_t ide_read_data_pio( void ) {
120 if( idereg.readptr == NULL )
122 uint16_t rv = *idereg.readptr++;
125 if( idereg.datalen <=0 ) {
126 idereg.readptr = NULL;
127 idereg.status &= ~IDE_ST_DATA;
128 } else if( idereg.blockleft <= 0 ) {
129 ide_raise_interrupt();
130 idereg.blockleft = idereg.blocksize;
135 void ide_write_data_pio( uint16_t val ) {
136 if( idereg.writeptr == NULL )
138 *idereg.writeptr++ = val;
140 if( idereg.datalen <= 0 ) {
141 int len = ((unsigned char *)idereg.writeptr) - idereg.data;
142 idereg.writeptr = NULL;
143 idereg.status &= ~IDE_ST_DATA;
144 ide_write_buffer( idereg.data, len );
148 void ide_write_control( uint8_t val ) {
149 if( IS_IDE_IRQ_ENABLED() ) {
150 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
151 asic_clear_event( EVENT_IDE );
153 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
154 asic_event( EVENT_IDE );
156 idereg.control = val;
159 void ide_write_command( uint8_t val ) {
160 ide_clear_interrupt();
161 idereg.command = val;
163 case IDE_CMD_RESET_DEVICE:
167 ide_set_write_buffer(command_buffer,12);
169 case IDE_CMD_SET_FEATURE:
170 switch( idereg.feature ) {
171 case IDE_FEAT_SET_TRANSFER_MODE:
172 switch( idereg.count & 0xF8 ) {
174 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
176 case IDE_XFER_PIO_FLOW:
177 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
179 case IDE_XFER_MULTI_DMA:
180 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
182 case IDE_XFER_ULTRA_DMA:
183 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
186 INFO( "Setting unknown transfer mode: %02X", idereg.count );
191 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
193 ide_raise_interrupt( );
196 WARN( "IDE: Unimplemented command: %02X", val );
198 idereg.status |= IDE_ST_READY | IDE_ST_SERV;
201 void ide_packet_command( unsigned char *cmd )
205 int blocksize = idereg.lba1 + (idereg.lba2<<8);
207 ide_raise_interrupt( );
208 /* Okay we have the packet in the command buffer */
209 WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
210 fwrite_dump( (unsigned char *)cmd, 12, stderr );
212 case PKT_CMD_IDENTIFY:
213 /* NB: Bios sets cmd[4] = 0x08, no idea what this is for;
214 * different values here appear to have no effect.
216 length = *((uint16_t*)(cmd+2));
217 if( length > sizeof(gdrom_ident) )
218 length = sizeof(gdrom_ident);
219 ide_set_read_buffer(gdrom_ident, length, blocksize);
221 case PKT_CMD_READ_TOC:
224 case PKT_CMD_READ_SECTOR:
225 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
226 length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
227 if( gdrom_disc == NULL ) {
228 ide_set_error( 0x50 );
232 if( gdrom_disc->read_data_sectors( lba, length ) == FALSE ) {
233 ide_set_error( 0x50 );
242 void ide_write_buffer( unsigned char *data, int datalen ) {
243 switch( idereg.command ) {
245 ide_packet_command( data );
253 * This method is called from the ASIC side when a DMA read request is
254 * initiated. If there is a pending DMA transfer already, we copy the
255 * data immediately, otherwise we record the DMA buffer for use when we
256 * get to actually doing the transfer.
258 void ide_dma_read_req( uint32_t addr, uint32_t length )
.