filename | src/gdrom/ide.c |
changeset | 152:d42a4c5cc709 |
prev | 149:d88dd2e9a190 |
next | 158:a0a82246b44e |
author | nkeynes |
date | Thu Jun 15 10:25:45 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add P4 I/O tracing Add ability to set I/O trace by region address |
view | annotate | diff | log | raw |
1 /**
2 * $Id: ide.c,v 1.14 2006-05-23 13:11:45 nkeynes Exp $
3 *
4 * IDE interface implementation
5 *
6 *
7 * Note: All references to read/write are from the host's point of view.
8 *
9 * See: INF-8020
10 * Copyright (c) 2005 Nathan Keynes.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
23 #define MODULE ide_module
25 #include <assert.h>
26 #include <stdlib.h>
27 #include "dream.h"
28 #include "asic.h"
29 #include "gdrom/ide.h"
30 #include "gdrom/gdrom.h"
31 #include "gdrom/packet.h"
33 #define MAX_WRITE_BUF 4096
34 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
35 #define DEFAULT_DATA_SECTORS 8
37 static void ide_init( void );
38 static void ide_reset( void );
39 static void ide_save_state( FILE *f );
40 static int ide_load_state( FILE *f );
41 static void ide_raise_interrupt( void );
42 static void ide_clear_interrupt( void );
43 static void ide_packet_command( unsigned char *data );
45 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
46 NULL, ide_save_state, ide_load_state };
48 struct ide_registers idereg;
49 unsigned char *data_buffer = NULL;
50 uint32_t data_buffer_len = 0;
52 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
53 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
55 /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */
56 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
57 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
58 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
59 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
62 static void ide_init( void )
63 {
64 ide_reset();
65 data_buffer_len = DEFAULT_DATA_SECTORS;
66 data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len );
67 assert( data_buffer != NULL );
68 }
70 static void ide_reset( void )
71 {
72 ide_clear_interrupt();
73 idereg.error = 0x01;
74 idereg.count = 0x01;
75 idereg.lba0 = /* 0x21; */ 0x81;
76 idereg.lba1 = 0x14;
77 idereg.lba2 = 0xeb;
78 idereg.feature = 0; /* Indeterminate really */
79 idereg.status = 0x00;
80 idereg.device = 0x00;
81 idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
82 idereg.state = IDE_STATE_IDLE;
83 memset( idereg.gdrom_sense, '\0', 10 );
84 idereg.data_offset = -1;
85 idereg.data_length = -1;
86 }
88 static void ide_save_state( FILE *f )
89 {
90 fwrite( &idereg, sizeof(idereg), 1, f );
91 fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
92 fwrite( data_buffer, data_buffer_len, 1, f );
93 }
95 static int ide_load_state( FILE *f )
96 {
97 uint32_t length;
98 fread( &idereg, sizeof(idereg), 1, f );
99 fread( &length, sizeof(uint32_t), 1, f );
100 if( length > data_buffer_len ) {
101 if( data_buffer != NULL )
102 free( data_buffer );
103 data_buffer = malloc( length );
104 assert( data_buffer != NULL );
105 data_buffer_len = length;
106 }
107 fread( data_buffer, length, 1, f );
108 return 0;
109 }
111 /************************ State transitions *************************/
113 /**
114 * Begin command packet write to the device. This is always 12 bytes of PIO data
115 */
116 static void ide_start_command_packet_write( )
117 {
118 idereg.state = IDE_STATE_CMD_WRITE;
119 idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
120 idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
121 idereg.count = IDE_COUNT_CD;
122 idereg.data_offset = 0;
123 idereg.data_length = 12;
124 }
126 /**
127 * Begin PIO read from the device. The data is assumed to already be
128 * in the buffer at this point.
129 */
130 static void ide_start_read( int length, int blocksize, gboolean dma )
131 {
132 idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
133 idereg.count = IDE_COUNT_IO;
134 idereg.data_length = length;
135 idereg.data_offset = 0;
136 if( dma ) {
137 idereg.state = IDE_STATE_DMA_READ;
138 idereg.status |= IDE_STATUS_DMRD;
139 } else {
140 idereg.state = IDE_STATE_PIO_READ;
141 idereg.lba1 = length & 0xFF;
142 idereg.lba2 = (length >> 8) & 0xFF;
143 // idereg.lba1 = blocksize & 0xFF;
144 // idereg.lba2 = blocksize >> 8;
145 idereg.block_length = blocksize;
146 idereg.block_left = blocksize;
147 }
148 }
150 static void ide_start_packet_read( int length, int blocksize )
151 {
152 ide_start_read( length, blocksize, idereg.feature & IDE_FEAT_DMA ? TRUE : FALSE );
153 }
155 static void ide_raise_interrupt( void )
156 {
157 if( idereg.intrq_pending == 0 ) {
158 idereg.intrq_pending = 1;
159 if( IS_IDE_IRQ_ENABLED() )
160 asic_event( EVENT_IDE );
161 }
162 }
164 static void ide_clear_interrupt( void )
165 {
166 if( idereg.intrq_pending != 0 ) {
167 idereg.intrq_pending = 0;
168 if( IS_IDE_IRQ_ENABLED() )
169 asic_clear_event( EVENT_IDE );
170 }
171 }
173 static void ide_set_error( int error_code )
174 {
175 idereg.status = 0x51;
176 idereg.error = error_code;
177 }
179 uint8_t ide_read_status( void )
180 {
181 if( (idereg.status & IDE_STATUS_BSY) == 0 )
182 ide_clear_interrupt();
183 return idereg.status;
184 }
186 uint16_t ide_read_data_pio( void ) {
187 if( idereg.state == IDE_STATE_PIO_READ ) {
188 uint16_t rv = READ_BUFFER();
189 idereg.data_offset += 2;
190 idereg.block_left -= 2;
191 if( idereg.data_offset >= idereg.data_length ) {
192 idereg.state = IDE_STATE_IDLE;
193 idereg.status &= ~IDE_STATUS_DRQ;
194 idereg.data_offset = -1;
195 ide_raise_interrupt();
196 } else if( idereg.block_left <= 0 ) {
197 idereg.block_left = idereg.block_length;
198 ide_raise_interrupt();
199 }
200 return rv;
201 } else {
202 return 0xFFFF;
203 }
204 }
207 /**
208 * DMA read request
209 *
210 * This method is called from the ASIC side when a DMA read request is
211 * initiated. If there is a pending DMA transfer already, we copy the
212 * data immediately, otherwise we record the DMA buffer for use when we
213 * get to actually doing the transfer.
214 * @return number of bytes transfered
215 */
216 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
217 {
218 if( idereg.state == IDE_STATE_DMA_READ ) {
219 int xferlen = length;
220 int remaining = idereg.data_length - idereg.data_offset;
221 if( xferlen > remaining )
222 xferlen = remaining;
223 mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
224 idereg.data_offset += xferlen;
225 if( idereg.data_offset >= idereg.data_length ) {
226 idereg.data_offset = -1;
227 idereg.state = IDE_STATE_IDLE;
228 idereg.status &= ~IDE_STATUS_DRQ;
229 ide_raise_interrupt();
230 }
231 return xferlen;
232 }
233 return 0;
234 }
237 void ide_write_data_pio( uint16_t val ) {
238 if( idereg.state == IDE_STATE_CMD_WRITE ) {
239 WRITE_BUFFER(val);
240 idereg.data_offset+=2;
241 if( idereg.data_offset >= idereg.data_length ) {
242 idereg.state = IDE_STATE_BUSY;
243 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
244 idereg.data_offset = -1;
245 ide_packet_command(data_buffer);
246 }
247 } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
248 WRITE_BUFFER(val);
249 if( idereg.data_offset >= idereg.data_length ) {
250 idereg.state = IDE_STATE_BUSY;
251 idereg.data_offset = -1;
252 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
253 /* ??? - no data writes yet anyway */
254 }
255 }
256 }
258 void ide_write_control( uint8_t val ) {
259 if( IS_IDE_IRQ_ENABLED() ) {
260 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
261 asic_clear_event( EVENT_IDE );
262 } else {
263 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
264 asic_event( EVENT_IDE );
265 }
266 idereg.control = val;
267 }
269 void ide_write_command( uint8_t val ) {
270 ide_clear_interrupt();
271 idereg.command = val;
272 switch( val ) {
273 case IDE_CMD_RESET_DEVICE:
274 ide_reset();
275 break;
276 case IDE_CMD_PACKET:
277 ide_start_command_packet_write();
278 break;
279 case IDE_CMD_SET_FEATURE:
280 switch( idereg.feature ) {
281 case IDE_FEAT_SET_TRANSFER_MODE:
282 switch( idereg.count & 0xF8 ) {
283 case IDE_XFER_PIO:
284 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
285 break;
286 case IDE_XFER_PIO_FLOW:
287 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
288 break;
289 case IDE_XFER_MULTI_DMA:
290 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
291 break;
292 case IDE_XFER_ULTRA_DMA:
293 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
294 break;
295 default:
296 INFO( "Setting unknown transfer mode: %02X", idereg.count );
297 break;
298 }
299 break;
300 default:
301 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
302 }
303 ide_raise_interrupt( );
304 break;
305 default:
306 WARN( "IDE: Unimplemented command: %02X", val );
307 }
308 idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);
309 }
311 void ide_set_packet_result( uint16_t result )
312 {
313 idereg.gdrom_sense[0] = 0xf0;
314 idereg.gdrom_sense[2] = result & 0xFF;
315 idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
316 idereg.error = (result & 0x0F) << 4;
317 if( result != 0 ) {
318 idereg.status = 0x51;
319 } else {
320 idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
321 }
322 }
324 /**
325 * Execute a packet command. This particular method is responsible for parsing
326 * the command buffers (12 bytes), and generating the appropriate responses,
327 * although the actual implementation is mostly delegated to gdrom.c
328 */
329 void ide_packet_command( unsigned char *cmd )
330 {
331 uint32_t length, datalen;
332 uint32_t lba, status;
333 int mode;
334 int blocksize = idereg.lba1 + (idereg.lba2<<8);
336 ide_raise_interrupt( );
337 /* Okay we have the packet in the command buffer */
338 WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
339 fwrite_dump( (unsigned char *)cmd, 12, stderr );
340 switch( cmd[0] ) {
341 case PKT_CMD_TEST_READY:
342 if( !gdrom_is_mounted() ) {
343 ide_set_packet_result( PKT_ERR_NODISC );
344 return;
345 }
346 ide_set_packet_result( 0 );
347 idereg.status = 0x50;
348 return;
349 break;
350 case PKT_CMD_IDENTIFY:
351 lba = cmd[2];
352 if( lba >= sizeof(gdrom_ident) ) {
353 ide_set_error(PKT_ERR_BADFIELD);
354 return;
355 }
356 length = cmd[4];
357 if( lba+length > sizeof(gdrom_ident) )
358 length = sizeof(gdrom_ident) - lba;
359 memcpy( data_buffer, gdrom_ident + lba, length );
360 ide_start_packet_read( length, blocksize );
361 break;
362 case PKT_CMD_SENSE:
363 length = cmd[4];
364 if( length > 10 )
365 length = 10;
366 memcpy( data_buffer, idereg.gdrom_sense, length );
367 ide_start_packet_read( length, blocksize );
368 break;
369 case PKT_CMD_READ_TOC:
370 length = (cmd[3]<<8) | cmd[4];
371 if( length > sizeof(struct gdrom_toc) )
372 length = sizeof(struct gdrom_toc);
374 status = gdrom_get_toc( data_buffer );
375 if( status != PKT_ERR_OK ) {
376 ide_set_packet_result( status );
377 return;
378 }
379 ide_start_packet_read( length, blocksize );
380 break;
381 case PKT_CMD_DISC_INFO:
382 length = cmd[4];
383 if( length > 6 )
384 length = 6;
385 status = gdrom_get_info( data_buffer, cmd[2] );
386 if( status != PKT_ERR_OK ) {
387 ide_set_packet_result( status );
388 return;
389 }
390 ide_start_packet_read( length, blocksize );
391 break;
392 case PKT_CMD_READ_SECTOR:
393 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
394 length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
395 if( length > data_buffer_len ) {
396 do {
397 data_buffer_len = data_buffer_len << 1;
398 } while( data_buffer_len < length );
399 data_buffer = realloc( data_buffer, data_buffer_len );
400 }
402 switch( cmd[1] ) {
403 case 0x20: mode = GDROM_MODE1; break;
404 case 0x24: mode = GDROM_GD; break;
405 case 0x28: mode = GDROM_MODE1; break; /* ??? */
406 case 0x30: mode = GDROM_RAW; break;
407 default:
408 ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
409 ide_set_packet_result( PKT_ERR_BADFIELD );
410 return;
411 }
412 datalen = data_buffer_len;
413 status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
414 if( status != 0 ) {
415 ide_set_packet_result( status );
416 idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
417 idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
418 idereg.gdrom_sense[7] = lba & 0xFF;
419 return;
420 }
421 ide_start_packet_read( datalen, blocksize );
422 break;
423 case PKT_CMD_SPIN_UP:
424 /* do nothing? */
425 break;
426 default:
427 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
428 return;
429 }
430 ide_set_packet_result( PKT_ERR_OK );
431 }
.