filename | src/gdrom/ide.c |
changeset | 1075:1a21750d300c |
prev | 1023:264e2fd90be8 |
next | 1097:d4807997e450 |
author | nkeynes |
date | Fri Jul 31 13:45:32 2009 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Remove or change the level of a bunch of INFO messages that shouldn't really be INFO level |
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/gddriver.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 if( fread( &idereg, sizeof(idereg), 1, f ) != 1 ||
178 fread( data_buffer, MAX_SECTOR_SIZE, 1, f ) != 1 ) {
179 return -1;
180 }
181 return 0;
182 }
184 /************************ State transitions *************************/
186 void ide_set_packet_result( uint16_t result )
187 {
188 idereg.gdrom_sense[0] = 0xf0;
189 idereg.gdrom_sense[2] = result & 0xFF;
190 idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
191 idereg.error = (result & 0x0F) << 4;
192 idereg.count = 3;
193 if( result != 0 ) {
194 idereg.status = 0x51;
195 idereg.state = IDE_STATE_IDLE;
196 ide_raise_interrupt();
197 } else {
198 idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
199 }
200 }
202 /**
203 * Begin command packet write to the device. This is always 12 bytes of PIO data
204 */
205 static void ide_start_command_packet_write( )
206 {
207 idereg.state = IDE_STATE_CMD_WRITE;
208 idereg.status = 0x58;
209 idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
210 idereg.count = IDE_COUNT_CD;
211 idereg.data_offset = 0;
212 idereg.data_length = 12;
213 }
215 /**
216 * Begin PIO/DMA read from the device. The data is assumed to already be
217 * in the buffer at this point.
218 */
219 static void ide_start_read( int length, gboolean dma )
220 {
221 idereg.count = IDE_COUNT_IO;
222 idereg.data_length = length;
223 idereg.data_offset = 0;
224 if( dma ) {
225 idereg.state = IDE_STATE_DMA_READ;
226 idereg.status = 0xD0;
227 } else {
228 idereg.state = IDE_STATE_PIO_READ;
229 idereg.status = 0x58;
230 idereg.lba1 = length & 0xFF;
231 idereg.lba2 = length >> 8;
232 ide_raise_interrupt( );
233 }
234 }
236 static void ide_start_write( int length, gboolean dma )
237 {
238 idereg.count = 0;
239 idereg.data_length = length;
240 idereg.data_offset = 0;
241 if( dma ) {
242 idereg.state = IDE_STATE_DMA_WRITE;
243 idereg.status = 0xD0;
244 } else {
245 idereg.state = IDE_STATE_PIO_WRITE;
246 idereg.status = 0x58;
247 idereg.lba1 = length & 0xFF;
248 idereg.lba2 = length >> 8;
249 ide_raise_interrupt( );
250 }
251 }
253 static void ide_start_packet_read( int length, int sector_count )
254 {
255 idereg.sectors_left = sector_count;
256 ide_set_packet_result( PKT_ERR_OK );
257 ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
258 }
260 static void ide_start_packet_write( int length, int sector_count )
261 {
262 idereg.sectors_left = sector_count;
263 ide_set_packet_result( PKT_ERR_OK );
264 ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
265 }
267 static void ide_raise_interrupt( void )
268 {
269 if( idereg.intrq_pending == 0 ) {
270 idereg.intrq_pending = 1;
271 if( IS_IDE_IRQ_ENABLED() )
272 asic_event( EVENT_IDE );
273 }
274 }
276 static void ide_clear_interrupt( void )
277 {
278 if( idereg.intrq_pending != 0 ) {
279 idereg.intrq_pending = 0;
280 if( IS_IDE_IRQ_ENABLED() )
281 asic_clear_event( EVENT_IDE );
282 }
283 }
285 static void ide_set_error( int error_code )
286 {
287 idereg.status = 0x51;
288 idereg.error = error_code;
289 }
291 uint8_t ide_read_status( void )
292 {
293 if( (idereg.status & IDE_STATUS_BSY) == 0 )
294 ide_clear_interrupt();
295 return idereg.status;
296 }
298 uint16_t ide_read_data_pio( void ) {
299 if( idereg.state == IDE_STATE_PIO_READ ) {
300 uint16_t rv = READ_BUFFER();
301 idereg.data_offset += 2;
302 if( idereg.data_offset >= idereg.data_length ) {
303 idereg.state = IDE_STATE_IDLE;
304 idereg.status &= ~IDE_STATUS_DRQ;
305 idereg.data_offset = -1;
306 idereg.count = 3; /* complete */
307 ide_raise_interrupt();
308 if( idereg.sectors_left > 0 ) {
309 ide_read_next_sector();
310 }
311 }
312 return rv;
313 } else {
314 return 0xFFFF;
315 }
316 }
319 /**
320 * DMA read request
321 *
322 * This method is called from the ASIC side when a DMA read request is
323 * initiated. If there is a pending DMA transfer already, we copy the
324 * data immediately, otherwise we record the DMA buffer for use when we
325 * get to actually doing the transfer.
326 * @return number of bytes transfered
327 */
328 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
329 {
330 uint32_t xfercount = 0;
331 while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
332 int xferlen = length - xfercount;
333 int remaining = idereg.data_length - idereg.data_offset;
334 if( xferlen > remaining ) {
335 xferlen = remaining;
336 }
337 mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
338 xfercount += xferlen;
339 addr += xferlen;
340 idereg.data_offset += xferlen;
341 if( idereg.data_offset >= idereg.data_length ) {
342 if( idereg.sectors_left > 0 ) {
343 ide_read_next_sector();
344 } else {
345 idereg.data_offset = -1;
346 idereg.state = IDE_STATE_IDLE;
347 idereg.status = 0x50;
348 idereg.count = 0x03;
349 ide_raise_interrupt();
350 break;
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 DEBUG( "Set PIO default mode: %d", idereg.count&0x07 );
415 break;
416 case IDE_XFER_PIO_FLOW:
417 DEBUG( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
418 break;
419 case IDE_XFER_MULTI_DMA:
420 DEBUG( "Set Multiword DMA mode: %d", idereg.count&0x07 );
421 break;
422 case IDE_XFER_ULTRA_DMA:
423 DEBUG( "Set Ultra DMA mode: %d", idereg.count&0x07 );
424 break;
425 default:
426 DEBUG( "Setting unknown transfer mode: %02X", idereg.count );
427 break;
428 }
429 break;
430 default:
431 DEBUG( "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 DEBUG( "IDE: Unimplemented command: %02X", val );
441 }
442 }
444 uint8_t ide_get_drive_status( void )
445 {
446 return gdrom_disc_get_drive_status(gdrom_disc);
447 }
449 #define REQUIRE_DISC() if( gdrom_disc == NULL || gdrom_disc->disc_type == IDE_DISC_NONE ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
451 /**
452 * Read the next sector from the active read, if any
453 */
454 static void ide_read_next_sector( void )
455 {
456 uint32_t sector_size;
457 REQUIRE_DISC();
458 gdrom_error_t status =
459 gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode,
460 data_buffer, §or_size );
461 if( status != PKT_ERR_OK ) {
462 ide_set_packet_result( status );
463 idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
464 idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
465 idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
466 WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
467 } else {
468 idereg.current_lba++;
469 idereg.sectors_left--;
470 ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
471 }
472 }
474 /**
475 * Execute a packet command. This particular method is responsible for parsing
476 * the command buffers (12 bytes), and generating the appropriate responses,
477 * although the actual implementation is mostly delegated to gdrom.c
478 */
479 void ide_packet_command( unsigned char *cmd )
480 {
481 uint32_t length;
482 uint32_t lba, status;
484 /* Okay we have the packet in the command buffer */
485 DEBUG( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
486 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
487 cmd[8], cmd[9], cmd[10], cmd[11] );
489 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
490 ide_set_packet_result( PKT_ERR_RESET );
491 idereg.was_reset = FALSE;
492 return;
493 }
495 switch( cmd[0] ) {
496 case PKT_CMD_TEST_READY:
497 REQUIRE_DISC();
498 ide_set_packet_result( 0 );
499 ide_raise_interrupt();
500 idereg.status = 0x50;
501 break;
502 case PKT_CMD_DRIVE_STATUS:
503 lba = cmd[2];
504 if( lba >= GDROM_DRIVE_STATUS_LENGTH ) {
505 ide_set_error(PKT_ERR_BADFIELD);
506 } else {
507 uint8_t status = ide_get_drive_status();
508 /* FIXME: Refactor read_position to avoid this kind of crud */
509 unsigned char tmp[16];
510 gdrom_disc_get_short_status( gdrom_disc, idereg.current_lba, tmp );
512 length = cmd[4];
513 if( lba+length > GDROM_DRIVE_STATUS_LENGTH )
514 length = GDROM_DRIVE_STATUS_LENGTH - lba;
515 char data[10];
516 data[0] = status & 0x0F;
517 data[1] = status & 0xF0;
518 data[2] = tmp[4];
519 data[3] = tmp[5];
520 data[4] = tmp[6];
521 data[5] = tmp[11];
522 data[6] = tmp[12];
523 data[7] = tmp[13];
524 data[8] = 0;
525 data[9] = 0;
526 memcpy( data_buffer, data + lba, length );
527 ide_start_packet_read( length, 0 );
528 }
529 break;
530 case PKT_CMD_MODE_SENSE:
531 lba = cmd[2];
532 if( lba >= GDROM_MODE_LENGTH ) {
533 ide_set_error(PKT_ERR_BADFIELD);
534 } else {
535 length = cmd[4];
536 if( lba+length > GDROM_MODE_LENGTH )
537 length = GDROM_MODE_LENGTH - lba;
538 memcpy( data_buffer, idereg.gdrom_mode + lba, length );
539 ide_start_packet_read( length, 0 );
540 }
541 break;
542 case PKT_CMD_MODE_SELECT:
543 lba = cmd[2];
544 if( lba >= GDROM_MODE_LENGTH ) {
545 ide_set_error(PKT_ERR_BADFIELD);
546 } else {
547 length = cmd[4];
548 if( lba+length > GDROM_MODE_LENGTH )
549 length = GDROM_MODE_LENGTH - lba;
550 idereg.current_lba = lba;
551 ide_start_packet_write( length, 0 );
552 }
553 break;
554 case PKT_CMD_SENSE:
555 length = cmd[4];
556 if( length > 10 )
557 length = 10;
558 memcpy( data_buffer, idereg.gdrom_sense, length );
559 ide_start_packet_read( length, 0 );
560 break;
561 case PKT_CMD_READ_TOC:
562 REQUIRE_DISC();
563 length = (cmd[3]<<8) | cmd[4];
564 if( length > GDROM_TOC_SIZE )
565 length = GDROM_TOC_SIZE;
567 status = gdrom_disc_get_toc( gdrom_disc, data_buffer );
568 if( status != PKT_ERR_OK ) {
569 ide_set_packet_result( status );
570 } else {
571 ide_start_packet_read( length, 0 );
572 }
573 break;
574 case PKT_CMD_SESSION_INFO:
575 REQUIRE_DISC();
576 length = cmd[4];
577 if( length > 6 )
578 length = 6;
579 status = gdrom_disc_get_session_info( gdrom_disc, cmd[2], data_buffer );
580 if( status != PKT_ERR_OK ) {
581 ide_set_packet_result( status );
582 } else {
583 ide_start_packet_read( length, 0 );
584 }
585 break;
586 case PKT_CMD_PLAY_AUDIO:
587 REQUIRE_DISC();
588 ide_set_packet_result( 0 );
589 ide_raise_interrupt();
590 idereg.status = 0x50;
591 break;
592 case PKT_CMD_READ_SECTOR:
593 REQUIRE_DISC();
594 idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
595 idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
596 idereg.current_mode = cmd[1];
597 ide_read_next_sector();
598 break;
599 case PKT_CMD_SPIN_UP:
600 REQUIRE_DISC();
601 /* do nothing? */
602 ide_set_packet_result( PKT_ERR_OK );
603 ide_raise_interrupt();
604 break;
605 case PKT_CMD_STATUS:
606 REQUIRE_DISC();
607 length = cmd[4];
608 switch( cmd[1] ) {
609 case 0:
610 if( length > sizeof(gdrom_status) ) {
611 length = sizeof(gdrom_status);
612 }
613 memcpy( data_buffer, gdrom_status, length );
614 ide_start_packet_read( length, 0 );
615 break;
616 case 1:
617 if( length > 14 ) {
618 length = 14;
619 }
620 gdrom_disc_get_short_status( gdrom_disc, idereg.current_lba, data_buffer );
621 ide_start_packet_read( length, 0 );
622 break;
623 }
624 break;
625 case PKT_CMD_71:
626 /* This is a weird one. As far as I can tell it returns random garbage
627 * (and not even the same length each time, never mind the same data).
628 * For sake of something to do, it returns the results from a test dump
629 */
630 REQUIRE_DISC();
631 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
632 ide_start_packet_read( sizeof(gdrom_71), 0 );
633 break;
634 default:
635 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
636 return;
637 }
638 idereg.last_packet_command = cmd[0];
639 }
641 void ide_write_buffer( unsigned char *data, uint32_t length )
642 {
643 switch( idereg.last_packet_command ) {
644 case PKT_CMD_MODE_SELECT:
645 if( idereg.current_lba < 10 ) {
646 if( idereg.current_lba + length > 10 ) {
647 length = 10 - idereg.current_lba;
648 }
649 memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
650 }
651 break;
652 default:
653 WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
654 }
655 }
.