filename | src/gdrom/ide.c |
changeset | 561:533f6b478071 |
prev | 493:c8183f888b14 |
next | 629:2811e8a2debf |
author | nkeynes |
date | Sun Mar 16 04:49:19 2008 +0000 (16 years ago) |
branch | lxdream-render |
permissions | -rw-r--r-- |
last change | Use max-z rather than min-z for tri sort (still wrong for some cases of course, but consistent with prior behaviour) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
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 "mem.h"
29 #include "asic.h"
30 #include "gdrom/ide.h"
31 #include "gdrom/gdrom.h"
32 #include "gdrom/packet.h"
34 #define MAX_WRITE_BUF 4096
35 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
36 #define DEFAULT_DATA_SECTORS 8
38 static void ide_init( void );
39 static void ide_reset( void );
40 static uint32_t ide_run_slice( uint32_t nanosecs );
41 static void ide_save_state( FILE *f );
42 static int ide_load_state( FILE *f );
43 static void ide_raise_interrupt( void );
44 static void ide_clear_interrupt( void );
45 static void ide_packet_command( unsigned char *data );
46 static void ide_read_next_sector(void);
48 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, ide_run_slice,
49 NULL, ide_save_state, ide_load_state };
51 struct ide_registers idereg;
52 gdrom_disc_t gdrom_disc = NULL;
54 unsigned char data_buffer[MAX_SECTOR_SIZE];
56 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
57 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
59 /* 10 bytes followed by "SE REV 6.42990316" */
60 unsigned char default_gdrom_mode[GDROM_MODE_LENGTH] =
61 { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08,
62 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
63 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
65 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE, 0x1D, 0xD9, 0x89, 0x04, 0x28, 0x3A, 0x8E, 0x26, 0x5C, 0x95, 0x10, 0x5A,
66 0x0A, 0x99, 0xEE, 0xFB, 0x69, 0xCE, 0xD9, 0x63, 0x00, 0xF5, 0x0A, 0xBC, 0x2C, 0x0D, 0xF8, 0xE2,
67 0x05, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3D, 0x08, 0xD8, 0x8D, 0x08, 0x7A, 0x6D, 0x00, 0x35, 0x06,
68 0xBA, 0x66, 0x10, 0x00, 0x91, 0x08, 0x10, 0x29, 0xD0, 0x45, 0xDA, 0x00, 0x2D, 0x05, 0x69, 0x09,
69 0x00, 0x5E, 0x0F, 0x70, 0x86, 0x12, 0x6C, 0x77, 0x5A, 0xFB, 0xCD, 0x56, 0xFB, 0xF7, 0xB7, 0x00,
70 0x5D, 0x07, 0x19, 0x99, 0xF2, 0xAF, 0x00, 0x63, 0x03, 0x00, 0xF0, 0x10, 0xBE, 0xD7, 0xA0, 0x63,
71 0xFA, 0x84, 0xA7, 0x74, 0x94, 0xEF, 0xAD, 0xC2, 0xAC, 0x00, 0x78, 0x07, 0x9F, 0x57, 0x0B, 0x62,
72 0x00, 0xFE, 0x08, 0x08, 0x5D, 0x5A, 0x6A, 0x54, 0x00, 0xE2, 0x09, 0x93, 0x7E, 0x62, 0x2A, 0x5E,
73 0xDA, 0x00, 0x7E, 0x0F, 0xF0, 0x07, 0x01, 0x6D, 0x50, 0x86, 0xDD, 0x4A, 0x15, 0x54, 0xC7, 0xEC,
74 0x00, 0xF2, 0x0B, 0x07, 0xF8, 0x1A, 0xB0, 0x99, 0x3B, 0xF1, 0x36, 0x00, 0x94, 0x07, 0x34, 0xE3,
75 0xBC, 0x6E, 0x00, 0x34, 0x0D, 0x6F, 0xDA, 0xBD, 0xEE, 0xF7, 0xCC, 0xCE, 0x39, 0x7E, 0xE3, 0x00,
76 0x14, 0x08, 0xDC, 0xD2, 0xB9, 0xF9, 0x31, 0x00, 0xB0, 0x0C, 0x10, 0xA3, 0x45, 0x12, 0xC7, 0xCD,
77 0xBF, 0x05, 0x37, 0x00, 0xC4, 0x0D, 0x5F, 0xE0, 0x59, 0xBB, 0x01, 0x59, 0x03, 0xD6, 0x29, 0x9C,
78 0x00, 0x01, 0x0A, 0x09, 0xAA, 0xA8, 0xA8, 0x24, 0x0B, 0x66, 0x00, 0x5C, 0x05, 0xA5, 0xCE, 0x00,
79 0xC1, 0x0B, 0xB7, 0xA0, 0x6F, 0xE9, 0x2B, 0xCC, 0xB5, 0xFC, 0x00, 0x8D, 0x05, 0xF4, 0xAC, 0x00,
80 0x57, 0x04, 0xB6, 0x00, 0xFC, 0x03, 0x00, 0xC3, 0x10, 0x43, 0x3B, 0xBE, 0xA2, 0x96, 0xC3, 0x65,
81 0x9F, 0x9A, 0x88, 0xD5, 0x49, 0x68, 0x00, 0xDC, 0x11, 0x56, 0x23, 0x2D, 0xF9, 0xFC, 0xF5, 0x8B,
82 0x1B, 0xB1, 0xB7, 0x10, 0x21, 0x1C, 0x12, 0x00, 0x0D, 0x0D, 0xEB, 0x86, 0xA2, 0x49, 0x8D, 0x8D,
83 0xBE, 0xA1, 0x6D, 0x53, 0x00, 0xE1, 0x0A, 0x8E, 0x67, 0xAA, 0x16, 0x79, 0x39, 0x59, 0x00, 0x36,
84 0x0B, 0x2A, 0x4E, 0xAE, 0x51, 0x4B, 0xD0, 0x66, 0x33, 0x00, 0x8A, 0x07, 0xCD, 0x6F, 0xBA, 0x92,
85 0x00, 0x1A, 0x0E, 0xDF, 0x4A, 0xB3, 0x77, 0x1F, 0xA5, 0x90, 0x19, 0xFA, 0x59, 0xD7, 0x00, 0x04,
86 0x0F, 0xAC, 0xCA, 0x9F, 0xA4, 0xFC, 0x6D, 0x90, 0x86, 0x9E, 0x1F, 0x44, 0x40, 0x00, 0x9F, 0x04,
87 0x56, 0x00, 0x22, 0x03, 0x00, 0xB8, 0x10, 0x2C, 0x7A, 0x53, 0xA4, 0xBF, 0xA3, 0x90, 0x90, 0x14,
88 0x9D, 0x46, 0x6C, 0x96, 0x00, 0xC6, 0x0B, 0x9B, 0xBB, 0xB0, 0xAE, 0x60, 0x92, 0x8E, 0x0C, 0x00,
89 0x14, 0x06, 0x4B, 0xAE, 0x7F, 0x00, 0x5C, 0x0B, 0x23, 0xFA, 0xE7, 0x51, 0xDA, 0x61, 0x49, 0x5E,
90 0x00, 0xD7, 0x0B, 0x01, 0xFC, 0x55, 0x31, 0x84, 0xC5, 0x0C, 0x98, 0x00, 0x97, 0x50, 0x6E, 0xF9,
91 0xEE, 0x75, 0x92, 0x53, 0xD3, 0x66, 0xA4, 0xAF, 0x3B, 0xFE, 0x7B, 0x27, 0x30, 0xBB, 0xB6, 0xF2,
92 0x76, 0x22, 0x45, 0x42, 0xCA, 0xF9, 0xF0, 0xDE, 0x9F, 0x45, 0x16, 0x68, 0x22, 0xB9, 0x84, 0x28,
93 0x8F, 0x2B, 0xB5, 0x5C, 0xD2, 0xF5, 0x45, 0x36, 0x3E, 0x76, 0xC6, 0xBF, 0x32, 0x5C, 0x41, 0xA6,
94 0x26, 0xC7, 0x82, 0x2F, 0x2E, 0xB5, 0x75, 0xC6, 0xE6, 0x67, 0x9E, 0x77, 0x94, 0xAF, 0x6A, 0x05,
95 0xC0, 0x05, 0x61, 0x71, 0x89, 0x5A, 0xB1, 0xD0, 0xFC, 0x7E, 0xC0, 0x9B, 0xCB, 0x3B, 0x69, 0xD9,
96 0x5F, 0xAF, 0xCA, 0xAB, 0x25, 0xD5, 0xBE, 0x8A, 0x6B, 0xB0, 0xFB, 0x61, 0x6C, 0xEB, 0x85, 0x6E,
97 0x7A, 0x48, 0xFF, 0x97, 0x91, 0x06, 0x3D, 0x4D, 0x68, 0xD3, 0x65, 0x83, 0x90, 0xA0, 0x08, 0x5C,
98 0xFC, 0xEE, 0x7C, 0x33, 0x43, 0x7F, 0x80, 0x52, 0x8B, 0x19, 0x72, 0xF2, 0xC9, 0xAB, 0x93, 0xAF,
99 0x16, 0xED, 0x36, 0x48, 0xAB, 0xC9, 0xD1, 0x03, 0xB3, 0xDC, 0x2F, 0xF2, 0x92, 0x3F, 0x0A, 0x19,
100 0x25, 0xE2, 0xEF, 0x7A, 0x22, 0xDA, 0xDB, 0xCB, 0x32, 0x12, 0x61, 0x49, 0x5B, 0x74, 0x7C, 0x65,
101 0x20, 0x89, 0x54, 0x9E, 0x0E, 0xC9, 0x52, 0xE3, 0xC9, 0x9A, 0x44, 0xC9, 0x5D, 0xA6, 0x77, 0xC0,
102 0xE7, 0x60, 0x91, 0x80, 0x50, 0x1F, 0x33, 0xB1, 0xCD, 0xAD, 0xF4, 0x0D, 0xBB, 0x08, 0xB1, 0xD0,
103 0x13, 0x95, 0xAE, 0xC9, 0xE2, 0x64, 0xA2, 0x65, 0xFB, 0x8F, 0xE9, 0xA2, 0x8A, 0xBC, 0x98, 0x81,
104 0x45, 0xB4, 0x55, 0x4E, 0xB9, 0x74, 0xB4, 0x50, 0x76, 0xBF, 0xF0, 0x45, 0xE7, 0xEE, 0x41, 0x64,
105 0x9F, 0xB5, 0xE0, 0xBB, 0x1C, 0xBB, 0x28, 0x66, 0x1B, 0xDD, 0x2B, 0x02, 0x66, 0xBF, 0xFD, 0x7D,
106 0x37, 0x35, 0x1D, 0x76, 0x21, 0xC3, 0x8F, 0xAF, 0xF6, 0xF9, 0xE9, 0x27, 0x48, 0xE7, 0x3D, 0x95,
107 0x74, 0x0C, 0x77, 0x88, 0x56, 0xD9, 0x84, 0xC8, 0x7D, 0x20, 0x31, 0x43, 0x53, 0xF1, 0xC1, 0xC7,
108 0xC9, 0xF7, 0x5C, 0xC0, 0xA6, 0x5A, 0x27, 0x0A, 0x41, 0xD4, 0x44, 0x94, 0x65, 0x4F, 0xE2, 0x53,
109 0x60, 0x0B, 0xD1, 0x23, 0x6C, 0x0C, 0xBC, 0x70, 0x6C, 0x26, 0x1A, 0x61, 0x1D, 0x35, 0x88, 0xEC,
110 0xB8, 0x15, 0xE3, 0xB4, 0x82, 0xEE, 0xB3, 0x21, 0xAC, 0x6C, 0xB7, 0x33, 0x6D, 0x78, 0x0C, 0x0D,
111 0xB4, 0x0B, 0x29, 0xF2, 0xD4, 0x8C, 0x3F, 0xDD, 0x3F, 0x47, 0xDD, 0xF2, 0xD8, 0x39, 0x57, 0x20,
112 0x28, 0xD8, 0xDD, 0x32, 0xE2, 0x6A, 0x47, 0x53, 0x57, 0xC6, 0xFA, 0x7A, 0x38, 0x30, 0x31, 0x8F,
113 0xE7, 0xD3, 0x84, 0x2B, 0x5D, 0x4F, 0x95, 0x98, 0xED, 0x0B, 0xD7, 0x50, 0x0C, 0x49, 0xDA, 0x59,
114 0x15, 0xF1, 0x39, 0xF3, 0x40, 0xDC, 0xDC, 0x25, 0x24, 0x56, 0x6E, 0xA9, 0x2F, 0xF0, 0x00, 0x00 };
117 char gdrom_status[] = {
118 0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
124 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
127 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
128 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
129 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
130 0x00, 0x40, 0x00, 0x00 };
133 static void ide_init( void )
134 {
135 ide_reset();
136 }
138 static void ide_reset( void )
139 {
140 ide_clear_interrupt();
141 idereg.error = 0x01;
142 idereg.count = 0x01;
143 idereg.lba0 = /* 0x21; */ 0x81;
144 idereg.lba1 = 0x14;
145 idereg.lba2 = 0xeb;
146 idereg.feature = 0; /* Indeterminate really */
147 idereg.status = 0x00;
148 idereg.device = 0x00;
149 idereg.state = IDE_STATE_IDLE;
150 memset( idereg.gdrom_sense, '\0', 10 );
151 memcpy( idereg.gdrom_mode, default_gdrom_mode, GDROM_MODE_LENGTH );
152 idereg.data_offset = -1;
153 idereg.data_length = -1;
154 idereg.last_read_track = 1;
155 idereg.current_lba = 150;
156 idereg.current_mode = 0x28;
157 idereg.sectors_left = 0;
158 idereg.was_reset = TRUE;
159 }
161 static uint32_t ide_run_slice( uint32_t nanosecs )
162 {
163 if( gdrom_disc != NULL && gdrom_disc->run_time_slice != NULL ) {
164 gdrom_disc->run_time_slice(gdrom_disc, nanosecs);
165 }
166 return nanosecs;
167 }
169 static void ide_save_state( FILE *f )
170 {
171 fwrite( &idereg, sizeof(idereg), 1, f );
172 fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
173 }
175 static int ide_load_state( FILE *f )
176 {
177 fread( &idereg, sizeof(idereg), 1, f );
178 fread( data_buffer, MAX_SECTOR_SIZE, 1, f );
179 return 0;
180 }
182 /************************ State transitions *************************/
184 void ide_set_packet_result( uint16_t result )
185 {
186 idereg.gdrom_sense[0] = 0xf0;
187 idereg.gdrom_sense[2] = result & 0xFF;
188 idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
189 idereg.error = (result & 0x0F) << 4;
190 idereg.count = 3;
191 if( result != 0 ) {
192 idereg.status = 0x51;
193 ide_raise_interrupt();
194 } else {
195 idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
196 }
197 }
199 /**
200 * Begin command packet write to the device. This is always 12 bytes of PIO data
201 */
202 static void ide_start_command_packet_write( )
203 {
204 idereg.state = IDE_STATE_CMD_WRITE;
205 idereg.status = 0x58;
206 idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
207 idereg.count = IDE_COUNT_CD;
208 idereg.data_offset = 0;
209 idereg.data_length = 12;
210 }
212 /**
213 * Begin PIO/DMA read from the device. The data is assumed to already be
214 * in the buffer at this point.
215 */
216 static void ide_start_read( int length, gboolean dma )
217 {
218 idereg.count = IDE_COUNT_IO;
219 idereg.data_length = length;
220 idereg.data_offset = 0;
221 if( dma ) {
222 idereg.state = IDE_STATE_DMA_READ;
223 idereg.status = 0xD0;
224 } else {
225 idereg.state = IDE_STATE_PIO_READ;
226 idereg.status = 0x58;
227 idereg.lba1 = length & 0xFF;
228 idereg.lba2 = length >> 8;
229 ide_raise_interrupt( );
230 }
231 }
233 static void ide_start_write( int length, gboolean dma )
234 {
235 idereg.count = 0;
236 idereg.data_length = length;
237 idereg.data_offset = 0;
238 if( dma ) {
239 idereg.state = IDE_STATE_DMA_WRITE;
240 idereg.status = 0xD0;
241 } else {
242 idereg.state = IDE_STATE_PIO_WRITE;
243 idereg.status = 0x58;
244 idereg.lba1 = length & 0xFF;
245 idereg.lba2 = length >> 8;
246 ide_raise_interrupt( );
247 }
248 }
250 static void ide_start_packet_read( int length, int sector_count )
251 {
252 idereg.sectors_left = sector_count;
253 ide_set_packet_result( PKT_ERR_OK );
254 ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
255 }
257 static void ide_start_packet_write( int length, int sector_count )
258 {
259 idereg.sectors_left = sector_count;
260 ide_set_packet_result( PKT_ERR_OK );
261 ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
262 }
264 static void ide_raise_interrupt( void )
265 {
266 if( idereg.intrq_pending == 0 ) {
267 idereg.intrq_pending = 1;
268 if( IS_IDE_IRQ_ENABLED() )
269 asic_event( EVENT_IDE );
270 }
271 }
273 static void ide_clear_interrupt( void )
274 {
275 if( idereg.intrq_pending != 0 ) {
276 idereg.intrq_pending = 0;
277 if( IS_IDE_IRQ_ENABLED() )
278 asic_clear_event( EVENT_IDE );
279 }
280 }
282 static void ide_set_error( int error_code )
283 {
284 idereg.status = 0x51;
285 idereg.error = error_code;
286 }
288 uint8_t ide_read_status( void )
289 {
290 if( (idereg.status & IDE_STATUS_BSY) == 0 )
291 ide_clear_interrupt();
292 return idereg.status;
293 }
295 uint16_t ide_read_data_pio( void ) {
296 if( idereg.state == IDE_STATE_PIO_READ ) {
297 uint16_t rv = READ_BUFFER();
298 idereg.data_offset += 2;
299 if( idereg.data_offset >= idereg.data_length ) {
300 idereg.state = IDE_STATE_IDLE;
301 idereg.status &= ~IDE_STATUS_DRQ;
302 idereg.data_offset = -1;
303 idereg.count = 3; /* complete */
304 ide_raise_interrupt();
305 if( idereg.sectors_left > 0 ) {
306 ide_read_next_sector();
307 }
308 }
309 return rv;
310 } else {
311 return 0xFFFF;
312 }
313 }
316 /**
317 * DMA read request
318 *
319 * This method is called from the ASIC side when a DMA read request is
320 * initiated. If there is a pending DMA transfer already, we copy the
321 * data immediately, otherwise we record the DMA buffer for use when we
322 * get to actually doing the transfer.
323 * @return number of bytes transfered
324 */
325 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
326 {
327 uint32_t xfercount = 0;
328 if( idereg.state == IDE_STATE_DMA_READ ) {
329 while( xfercount < length ) {
330 int xferlen = length - xfercount;
331 int remaining = idereg.data_length - idereg.data_offset;
332 if( xferlen > remaining ) {
333 xferlen = remaining;
334 }
335 mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
336 xfercount += xferlen;
337 addr += xferlen;
338 idereg.data_offset += xferlen;
339 if( idereg.data_offset >= idereg.data_length ) {
340 if( idereg.sectors_left > 0 ) {
341 ide_read_next_sector();
342 } else {
343 idereg.data_offset = -1;
344 idereg.state = IDE_STATE_IDLE;
345 idereg.status = 0x50;
346 idereg.count = 0x03;
347 ide_raise_interrupt();
348 asic_event( EVENT_IDE_DMA );
349 break;
350 }
351 }
352 }
353 }
354 return xfercount;
355 }
357 void ide_write_data_pio( uint16_t val ) {
358 if( idereg.state == IDE_STATE_CMD_WRITE ) {
359 WRITE_BUFFER(val);
360 idereg.data_offset+=2;
361 if( idereg.data_offset >= idereg.data_length ) {
362 idereg.state = IDE_STATE_BUSY;
363 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
364 idereg.data_offset = -1;
365 ide_packet_command(data_buffer);
366 }
367 } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
368 WRITE_BUFFER(val);
369 idereg.data_offset +=2;
370 if( idereg.data_offset >= idereg.data_length ) {
371 idereg.state = IDE_STATE_IDLE;
372 idereg.status &= ~IDE_STATUS_DRQ;
373 idereg.data_offset = -1;
374 idereg.count = 3; /* complete */
375 ide_raise_interrupt();
376 ide_write_buffer( data_buffer, idereg.data_length );
377 }
378 }
379 }
381 void ide_write_control( uint8_t val ) {
382 if( IS_IDE_IRQ_ENABLED() ) {
383 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
384 asic_clear_event( EVENT_IDE );
385 } else {
386 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
387 asic_event( EVENT_IDE );
388 }
389 idereg.control = val;
390 }
392 void ide_write_command( uint8_t val ) {
393 ide_clear_interrupt();
394 idereg.command = val;
395 switch( val ) {
396 case IDE_CMD_NOP: /* Effectively an "abort" */
397 idereg.state = IDE_STATE_IDLE;
398 idereg.status = 0x51;
399 idereg.error = 0x04;
400 idereg.data_offset = -1;
401 ide_raise_interrupt();
402 return;
403 case IDE_CMD_RESET_DEVICE:
404 ide_reset();
405 break;
406 case IDE_CMD_PACKET:
407 ide_start_command_packet_write();
408 break;
409 case IDE_CMD_SET_FEATURE:
410 switch( idereg.feature ) {
411 case IDE_FEAT_SET_TRANSFER_MODE:
412 switch( idereg.count & 0xF8 ) {
413 case IDE_XFER_PIO:
414 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
415 break;
416 case IDE_XFER_PIO_FLOW:
417 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
418 break;
419 case IDE_XFER_MULTI_DMA:
420 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
421 break;
422 case IDE_XFER_ULTRA_DMA:
423 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
424 break;
425 default:
426 INFO( "Setting unknown transfer mode: %02X", idereg.count );
427 break;
428 }
429 break;
430 default:
431 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
432 }
433 idereg.status = 0x50;
434 idereg.error = 0x00;
435 idereg.lba1 = 0x00;
436 idereg.lba2 = 0x00;
437 ide_raise_interrupt();
438 break;
439 default:
440 WARN( "IDE: Unimplemented command: %02X", val );
441 }
442 }
444 uint8_t ide_get_drive_status( void )
445 {
446 if( gdrom_disc == NULL ) {
447 return IDE_DISC_NONE;
448 } else {
449 return gdrom_disc->drive_status(gdrom_disc);
450 }
451 }
453 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
455 /**
456 * Read the next sector from the active read, if any
457 */
458 static void ide_read_next_sector( void )
459 {
460 uint32_t sector_size;
461 REQUIRE_DISC();
462 gdrom_error_t status =
463 gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode,
464 data_buffer, §or_size );
465 if( status != PKT_ERR_OK ) {
466 ide_set_packet_result( status );
467 idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
468 idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
469 idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
470 WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
471 } else {
472 idereg.current_lba++;
473 idereg.sectors_left--;
474 ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
475 }
476 }
478 /**
479 * Execute a packet command. This particular method is responsible for parsing
480 * the command buffers (12 bytes), and generating the appropriate responses,
481 * although the actual implementation is mostly delegated to gdrom.c
482 */
483 void ide_packet_command( unsigned char *cmd )
484 {
485 uint32_t length;
486 uint32_t lba, status;
488 /* Okay we have the packet in the command buffer */
489 INFO( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
490 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
491 cmd[8], cmd[9], cmd[10], cmd[11] );
493 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
494 ide_set_packet_result( PKT_ERR_RESET );
495 idereg.was_reset = FALSE;
496 return;
497 }
499 switch( cmd[0] ) {
500 case PKT_CMD_TEST_READY:
501 REQUIRE_DISC();
502 ide_set_packet_result( 0 );
503 ide_raise_interrupt();
504 idereg.status = 0x50;
505 break;
506 case PKT_CMD_MODE_SENSE:
507 lba = cmd[2];
508 if( lba >= GDROM_MODE_LENGTH ) {
509 ide_set_error(PKT_ERR_BADFIELD);
510 } else {
511 length = cmd[4];
512 if( lba+length > GDROM_MODE_LENGTH )
513 length = GDROM_MODE_LENGTH - lba;
514 memcpy( data_buffer, idereg.gdrom_mode + lba, length );
515 ide_start_packet_read( length, 0 );
516 }
517 break;
518 case PKT_CMD_MODE_SELECT:
519 lba = cmd[2];
520 if( lba >= GDROM_MODE_LENGTH ) {
521 ide_set_error(PKT_ERR_BADFIELD);
522 } else {
523 length = cmd[4];
524 if( lba+length > GDROM_MODE_LENGTH )
525 length = GDROM_MODE_LENGTH - lba;
526 idereg.current_lba = lba;
527 ide_start_packet_write( length, 0 );
528 }
529 break;
530 case PKT_CMD_SENSE:
531 length = cmd[4];
532 if( length > 10 )
533 length = 10;
534 memcpy( data_buffer, idereg.gdrom_sense, length );
535 ide_start_packet_read( length, 0 );
536 break;
537 case PKT_CMD_READ_TOC:
538 REQUIRE_DISC();
539 length = (cmd[3]<<8) | cmd[4];
540 if( length > sizeof(struct gdrom_toc) )
541 length = sizeof(struct gdrom_toc);
543 status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
544 if( status != PKT_ERR_OK ) {
545 ide_set_packet_result( status );
546 } else {
547 ide_start_packet_read( length, 0 );
548 }
549 break;
550 case PKT_CMD_SESSION_INFO:
551 REQUIRE_DISC();
552 length = cmd[4];
553 if( length > 6 )
554 length = 6;
555 status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
556 if( status != PKT_ERR_OK ) {
557 ide_set_packet_result( status );
558 } else {
559 ide_start_packet_read( length, 0 );
560 }
561 break;
562 case PKT_CMD_PLAY_AUDIO:
563 REQUIRE_DISC();
564 ide_set_packet_result( 0 );
565 ide_raise_interrupt();
566 idereg.status = 0x50;
567 break;
568 case PKT_CMD_READ_SECTOR:
569 REQUIRE_DISC();
570 idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
571 idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
572 idereg.current_mode = cmd[1];
573 ide_read_next_sector();
574 break;
575 case PKT_CMD_SPIN_UP:
576 REQUIRE_DISC();
577 /* do nothing? */
578 ide_set_packet_result( PKT_ERR_OK );
579 ide_raise_interrupt();
580 break;
581 case PKT_CMD_STATUS:
582 REQUIRE_DISC();
583 length = cmd[4];
584 switch( cmd[1] ) {
585 case 0:
586 if( length > sizeof(gdrom_status) ) {
587 length = sizeof(gdrom_status);
588 }
589 memcpy( data_buffer, gdrom_status, length );
590 ide_start_packet_read( length, 0 );
591 break;
592 case 1:
593 if( length > 14 ) {
594 length = 14;
595 }
596 gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
597 data_buffer[0] = 0x00;
598 data_buffer[1] = 0x15; /* audio status ? */
599 data_buffer[2] = 0x00;
600 data_buffer[3] = 0x0E;
601 ide_start_packet_read( length, 0 );
602 break;
603 }
604 break;
605 case PKT_CMD_71:
606 /* This is a weird one. As far as I can tell it returns random garbage
607 * (and not even the same length each time, never mind the same data).
608 * For sake of something to do, it returns the results from a test dump
609 */
610 REQUIRE_DISC();
611 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
612 ide_start_packet_read( sizeof(gdrom_71), 0 );
613 break;
614 default:
615 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
616 return;
617 }
618 idereg.last_packet_command = cmd[0];
619 }
621 void ide_write_buffer( unsigned char *data, uint32_t length )
622 {
623 switch( idereg.last_packet_command ) {
624 case PKT_CMD_MODE_SELECT:
625 if( idereg.current_lba < 10 ) {
626 if( idereg.current_lba + length > 10 ) {
627 length = 10 - idereg.current_lba;
628 }
629 memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
630 }
631 break;
632 default:
633 WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
634 }
635 }
.