filename | src/gdrom/ide.c |
changeset | 1097:d4807997e450 |
prev | 1075:1a21750d300c |
author | nkeynes |
date | Wed Feb 15 17:54:51 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Use GL_TEXTURE_2D instead of GL_TEXTURE_RECTANGLE_ARB for frame buffers, for systems that don't provide the latter (and there's not really much difference anyway). Add macro wrangling for GL_DEPTH24_STENCIL8 format |
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;
53 unsigned char data_buffer[MAX_SECTOR_SIZE];
55 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
56 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
58 /* 10 bytes followed by "SE REV 6.42990316" */
59 unsigned char default_gdrom_mode[GDROM_MODE_LENGTH] =
60 { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08,
61 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
62 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
64 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE, 0x1D, 0xD9, 0x89, 0x04, 0x28, 0x3A, 0x8E, 0x26, 0x5C, 0x95, 0x10, 0x5A,
65 0x0A, 0x99, 0xEE, 0xFB, 0x69, 0xCE, 0xD9, 0x63, 0x00, 0xF5, 0x0A, 0xBC, 0x2C, 0x0D, 0xF8, 0xE2,
66 0x05, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3D, 0x08, 0xD8, 0x8D, 0x08, 0x7A, 0x6D, 0x00, 0x35, 0x06,
67 0xBA, 0x66, 0x10, 0x00, 0x91, 0x08, 0x10, 0x29, 0xD0, 0x45, 0xDA, 0x00, 0x2D, 0x05, 0x69, 0x09,
68 0x00, 0x5E, 0x0F, 0x70, 0x86, 0x12, 0x6C, 0x77, 0x5A, 0xFB, 0xCD, 0x56, 0xFB, 0xF7, 0xB7, 0x00,
69 0x5D, 0x07, 0x19, 0x99, 0xF2, 0xAF, 0x00, 0x63, 0x03, 0x00, 0xF0, 0x10, 0xBE, 0xD7, 0xA0, 0x63,
70 0xFA, 0x84, 0xA7, 0x74, 0x94, 0xEF, 0xAD, 0xC2, 0xAC, 0x00, 0x78, 0x07, 0x9F, 0x57, 0x0B, 0x62,
71 0x00, 0xFE, 0x08, 0x08, 0x5D, 0x5A, 0x6A, 0x54, 0x00, 0xE2, 0x09, 0x93, 0x7E, 0x62, 0x2A, 0x5E,
72 0xDA, 0x00, 0x7E, 0x0F, 0xF0, 0x07, 0x01, 0x6D, 0x50, 0x86, 0xDD, 0x4A, 0x15, 0x54, 0xC7, 0xEC,
73 0x00, 0xF2, 0x0B, 0x07, 0xF8, 0x1A, 0xB0, 0x99, 0x3B, 0xF1, 0x36, 0x00, 0x94, 0x07, 0x34, 0xE3,
74 0xBC, 0x6E, 0x00, 0x34, 0x0D, 0x6F, 0xDA, 0xBD, 0xEE, 0xF7, 0xCC, 0xCE, 0x39, 0x7E, 0xE3, 0x00,
75 0x14, 0x08, 0xDC, 0xD2, 0xB9, 0xF9, 0x31, 0x00, 0xB0, 0x0C, 0x10, 0xA3, 0x45, 0x12, 0xC7, 0xCD,
76 0xBF, 0x05, 0x37, 0x00, 0xC4, 0x0D, 0x5F, 0xE0, 0x59, 0xBB, 0x01, 0x59, 0x03, 0xD6, 0x29, 0x9C,
77 0x00, 0x01, 0x0A, 0x09, 0xAA, 0xA8, 0xA8, 0x24, 0x0B, 0x66, 0x00, 0x5C, 0x05, 0xA5, 0xCE, 0x00,
78 0xC1, 0x0B, 0xB7, 0xA0, 0x6F, 0xE9, 0x2B, 0xCC, 0xB5, 0xFC, 0x00, 0x8D, 0x05, 0xF4, 0xAC, 0x00,
79 0x57, 0x04, 0xB6, 0x00, 0xFC, 0x03, 0x00, 0xC3, 0x10, 0x43, 0x3B, 0xBE, 0xA2, 0x96, 0xC3, 0x65,
80 0x9F, 0x9A, 0x88, 0xD5, 0x49, 0x68, 0x00, 0xDC, 0x11, 0x56, 0x23, 0x2D, 0xF9, 0xFC, 0xF5, 0x8B,
81 0x1B, 0xB1, 0xB7, 0x10, 0x21, 0x1C, 0x12, 0x00, 0x0D, 0x0D, 0xEB, 0x86, 0xA2, 0x49, 0x8D, 0x8D,
82 0xBE, 0xA1, 0x6D, 0x53, 0x00, 0xE1, 0x0A, 0x8E, 0x67, 0xAA, 0x16, 0x79, 0x39, 0x59, 0x00, 0x36,
83 0x0B, 0x2A, 0x4E, 0xAE, 0x51, 0x4B, 0xD0, 0x66, 0x33, 0x00, 0x8A, 0x07, 0xCD, 0x6F, 0xBA, 0x92,
84 0x00, 0x1A, 0x0E, 0xDF, 0x4A, 0xB3, 0x77, 0x1F, 0xA5, 0x90, 0x19, 0xFA, 0x59, 0xD7, 0x00, 0x04,
85 0x0F, 0xAC, 0xCA, 0x9F, 0xA4, 0xFC, 0x6D, 0x90, 0x86, 0x9E, 0x1F, 0x44, 0x40, 0x00, 0x9F, 0x04,
86 0x56, 0x00, 0x22, 0x03, 0x00, 0xB8, 0x10, 0x2C, 0x7A, 0x53, 0xA4, 0xBF, 0xA3, 0x90, 0x90, 0x14,
87 0x9D, 0x46, 0x6C, 0x96, 0x00, 0xC6, 0x0B, 0x9B, 0xBB, 0xB0, 0xAE, 0x60, 0x92, 0x8E, 0x0C, 0x00,
88 0x14, 0x06, 0x4B, 0xAE, 0x7F, 0x00, 0x5C, 0x0B, 0x23, 0xFA, 0xE7, 0x51, 0xDA, 0x61, 0x49, 0x5E,
89 0x00, 0xD7, 0x0B, 0x01, 0xFC, 0x55, 0x31, 0x84, 0xC5, 0x0C, 0x98, 0x00, 0x97, 0x50, 0x6E, 0xF9,
90 0xEE, 0x75, 0x92, 0x53, 0xD3, 0x66, 0xA4, 0xAF, 0x3B, 0xFE, 0x7B, 0x27, 0x30, 0xBB, 0xB6, 0xF2,
91 0x76, 0x22, 0x45, 0x42, 0xCA, 0xF9, 0xF0, 0xDE, 0x9F, 0x45, 0x16, 0x68, 0x22, 0xB9, 0x84, 0x28,
92 0x8F, 0x2B, 0xB5, 0x5C, 0xD2, 0xF5, 0x45, 0x36, 0x3E, 0x76, 0xC6, 0xBF, 0x32, 0x5C, 0x41, 0xA6,
93 0x26, 0xC7, 0x82, 0x2F, 0x2E, 0xB5, 0x75, 0xC6, 0xE6, 0x67, 0x9E, 0x77, 0x94, 0xAF, 0x6A, 0x05,
94 0xC0, 0x05, 0x61, 0x71, 0x89, 0x5A, 0xB1, 0xD0, 0xFC, 0x7E, 0xC0, 0x9B, 0xCB, 0x3B, 0x69, 0xD9,
95 0x5F, 0xAF, 0xCA, 0xAB, 0x25, 0xD5, 0xBE, 0x8A, 0x6B, 0xB0, 0xFB, 0x61, 0x6C, 0xEB, 0x85, 0x6E,
96 0x7A, 0x48, 0xFF, 0x97, 0x91, 0x06, 0x3D, 0x4D, 0x68, 0xD3, 0x65, 0x83, 0x90, 0xA0, 0x08, 0x5C,
97 0xFC, 0xEE, 0x7C, 0x33, 0x43, 0x7F, 0x80, 0x52, 0x8B, 0x19, 0x72, 0xF2, 0xC9, 0xAB, 0x93, 0xAF,
98 0x16, 0xED, 0x36, 0x48, 0xAB, 0xC9, 0xD1, 0x03, 0xB3, 0xDC, 0x2F, 0xF2, 0x92, 0x3F, 0x0A, 0x19,
99 0x25, 0xE2, 0xEF, 0x7A, 0x22, 0xDA, 0xDB, 0xCB, 0x32, 0x12, 0x61, 0x49, 0x5B, 0x74, 0x7C, 0x65,
100 0x20, 0x89, 0x54, 0x9E, 0x0E, 0xC9, 0x52, 0xE3, 0xC9, 0x9A, 0x44, 0xC9, 0x5D, 0xA6, 0x77, 0xC0,
101 0xE7, 0x60, 0x91, 0x80, 0x50, 0x1F, 0x33, 0xB1, 0xCD, 0xAD, 0xF4, 0x0D, 0xBB, 0x08, 0xB1, 0xD0,
102 0x13, 0x95, 0xAE, 0xC9, 0xE2, 0x64, 0xA2, 0x65, 0xFB, 0x8F, 0xE9, 0xA2, 0x8A, 0xBC, 0x98, 0x81,
103 0x45, 0xB4, 0x55, 0x4E, 0xB9, 0x74, 0xB4, 0x50, 0x76, 0xBF, 0xF0, 0x45, 0xE7, 0xEE, 0x41, 0x64,
104 0x9F, 0xB5, 0xE0, 0xBB, 0x1C, 0xBB, 0x28, 0x66, 0x1B, 0xDD, 0x2B, 0x02, 0x66, 0xBF, 0xFD, 0x7D,
105 0x37, 0x35, 0x1D, 0x76, 0x21, 0xC3, 0x8F, 0xAF, 0xF6, 0xF9, 0xE9, 0x27, 0x48, 0xE7, 0x3D, 0x95,
106 0x74, 0x0C, 0x77, 0x88, 0x56, 0xD9, 0x84, 0xC8, 0x7D, 0x20, 0x31, 0x43, 0x53, 0xF1, 0xC1, 0xC7,
107 0xC9, 0xF7, 0x5C, 0xC0, 0xA6, 0x5A, 0x27, 0x0A, 0x41, 0xD4, 0x44, 0x94, 0x65, 0x4F, 0xE2, 0x53,
108 0x60, 0x0B, 0xD1, 0x23, 0x6C, 0x0C, 0xBC, 0x70, 0x6C, 0x26, 0x1A, 0x61, 0x1D, 0x35, 0x88, 0xEC,
109 0xB8, 0x15, 0xE3, 0xB4, 0x82, 0xEE, 0xB3, 0x21, 0xAC, 0x6C, 0xB7, 0x33, 0x6D, 0x78, 0x0C, 0x0D,
110 0xB4, 0x0B, 0x29, 0xF2, 0xD4, 0x8C, 0x3F, 0xDD, 0x3F, 0x47, 0xDD, 0xF2, 0xD8, 0x39, 0x57, 0x20,
111 0x28, 0xD8, 0xDD, 0x32, 0xE2, 0x6A, 0x47, 0x53, 0x57, 0xC6, 0xFA, 0x7A, 0x38, 0x30, 0x31, 0x8F,
112 0xE7, 0xD3, 0x84, 0x2B, 0x5D, 0x4F, 0x95, 0x98, 0xED, 0x0B, 0xD7, 0x50, 0x0C, 0x49, 0xDA, 0x59,
113 0x15, 0xF1, 0x39, 0xF3, 0x40, 0xDC, 0xDC, 0x25, 0x24, 0x56, 0x6E, 0xA9, 0x2F, 0xF0, 0x00, 0x00 };
116 char gdrom_status[] = {
117 0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
123 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
126 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
127 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
128 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
129 0x00, 0x40, 0x00, 0x00 };
132 static void ide_init( void )
133 {
134 ide_reset();
135 }
137 static void ide_reset( void )
138 {
139 ide_clear_interrupt();
140 idereg.error = 0x01;
141 idereg.count = 0x01;
142 idereg.lba0 = /* 0x21; */ 0x81;
143 idereg.lba1 = 0x14;
144 idereg.lba2 = 0xeb;
145 idereg.feature = 0; /* Indeterminate really */
146 idereg.status = 0x00;
147 idereg.device = 0x00;
148 idereg.state = IDE_STATE_IDLE;
149 memset( idereg.gdrom_sense, '\0', 10 );
150 memcpy( idereg.gdrom_mode, default_gdrom_mode, GDROM_MODE_LENGTH );
151 idereg.data_offset = -1;
152 idereg.data_length = -1;
153 idereg.last_read_track = 1;
154 idereg.current_lba = 150;
155 idereg.current_mode = 0x28;
156 idereg.sectors_left = 0;
157 idereg.was_reset = TRUE;
158 }
160 static uint32_t ide_run_slice( uint32_t nanosecs )
161 {
162 gdrom_run_slice(nanosecs);
163 return nanosecs;
164 }
166 static void ide_save_state( FILE *f )
167 {
168 fwrite( &idereg, sizeof(idereg), 1, f );
169 fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
170 }
172 static int ide_load_state( FILE *f )
173 {
174 if( fread( &idereg, sizeof(idereg), 1, f ) != 1 ||
175 fread( data_buffer, MAX_SECTOR_SIZE, 1, f ) != 1 ) {
176 return -1;
177 }
178 return 0;
179 }
181 /************************ State transitions *************************/
183 void ide_set_packet_result( uint16_t result )
184 {
185 idereg.gdrom_sense[0] = 0xf0;
186 idereg.gdrom_sense[2] = result & 0xFF;
187 idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
188 idereg.error = (result & 0x0F) << 4;
189 idereg.count = 3;
190 if( result != 0 ) {
191 idereg.status = 0x51;
192 idereg.state = IDE_STATE_IDLE;
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 while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
329 int xferlen = length - xfercount;
330 int remaining = idereg.data_length - idereg.data_offset;
331 if( xferlen > remaining ) {
332 xferlen = remaining;
333 }
334 mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
335 xfercount += xferlen;
336 addr += xferlen;
337 idereg.data_offset += xferlen;
338 if( idereg.data_offset >= idereg.data_length ) {
339 if( idereg.sectors_left > 0 ) {
340 ide_read_next_sector();
341 } else {
342 idereg.data_offset = -1;
343 idereg.state = IDE_STATE_IDLE;
344 idereg.status = 0x50;
345 idereg.count = 0x03;
346 ide_raise_interrupt();
347 break;
348 }
349 }
350 }
351 return xfercount;
352 }
354 void ide_write_data_pio( uint16_t val ) {
355 if( idereg.state == IDE_STATE_CMD_WRITE ) {
356 WRITE_BUFFER(val);
357 idereg.data_offset+=2;
358 if( idereg.data_offset >= idereg.data_length ) {
359 idereg.state = IDE_STATE_BUSY;
360 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
361 idereg.data_offset = -1;
362 ide_packet_command(data_buffer);
363 }
364 } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
365 WRITE_BUFFER(val);
366 idereg.data_offset +=2;
367 if( idereg.data_offset >= idereg.data_length ) {
368 idereg.state = IDE_STATE_IDLE;
369 idereg.status &= ~IDE_STATUS_DRQ;
370 idereg.data_offset = -1;
371 idereg.count = 3; /* complete */
372 ide_raise_interrupt();
373 ide_write_buffer( data_buffer, idereg.data_length );
374 }
375 }
376 }
378 void ide_write_control( uint8_t val ) {
379 if( IS_IDE_IRQ_ENABLED() ) {
380 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
381 asic_clear_event( EVENT_IDE );
382 } else {
383 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
384 asic_event( EVENT_IDE );
385 }
386 idereg.control = val;
387 }
389 void ide_write_command( uint8_t val ) {
390 ide_clear_interrupt();
391 idereg.command = val;
392 switch( val ) {
393 case IDE_CMD_NOP: /* Effectively an "abort" */
394 idereg.state = IDE_STATE_IDLE;
395 idereg.status = 0x51;
396 idereg.error = 0x04;
397 idereg.data_offset = -1;
398 ide_raise_interrupt();
399 return;
400 case IDE_CMD_RESET_DEVICE:
401 ide_reset();
402 break;
403 case IDE_CMD_PACKET:
404 ide_start_command_packet_write();
405 break;
406 case IDE_CMD_SET_FEATURE:
407 switch( idereg.feature ) {
408 case IDE_FEAT_SET_TRANSFER_MODE:
409 switch( idereg.count & 0xF8 ) {
410 case IDE_XFER_PIO:
411 DEBUG( "Set PIO default mode: %d", idereg.count&0x07 );
412 break;
413 case IDE_XFER_PIO_FLOW:
414 DEBUG( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
415 break;
416 case IDE_XFER_MULTI_DMA:
417 DEBUG( "Set Multiword DMA mode: %d", idereg.count&0x07 );
418 break;
419 case IDE_XFER_ULTRA_DMA:
420 DEBUG( "Set Ultra DMA mode: %d", idereg.count&0x07 );
421 break;
422 default:
423 DEBUG( "Setting unknown transfer mode: %02X", idereg.count );
424 break;
425 }
426 break;
427 default:
428 DEBUG( "IDE: unimplemented feature: %02X", idereg.feature );
429 }
430 idereg.status = 0x50;
431 idereg.error = 0x00;
432 idereg.lba1 = 0x00;
433 idereg.lba2 = 0x00;
434 ide_raise_interrupt();
435 break;
436 default:
437 DEBUG( "IDE: Unimplemented command: %02X", val );
438 }
439 }
441 uint8_t ide_get_drive_status( void )
442 {
443 return gdrom_get_drive_status();
444 }
446 #define REQUIRE_DISC() if( gdrom_get_drive_status() == IDE_DISC_NONE ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
448 /**
449 * Read the next sector from the active read, if any
450 */
451 static void ide_read_next_sector( void )
452 {
453 size_t sector_size;
454 cdrom_error_t status = gdrom_read_cd( idereg.current_lba, 1, idereg.current_mode, data_buffer, §or_size );
455 if( status != PKT_ERR_OK ) {
456 ide_set_packet_result( status );
457 idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
458 idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
459 idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
460 WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
461 } else {
462 idereg.current_lba++;
463 idereg.sectors_left--;
464 ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
465 }
466 }
468 /**
469 * Execute a packet command. This particular method is responsible for parsing
470 * the command buffers (12 bytes), and generating the appropriate responses,
471 * although the actual implementation is mostly delegated to gdrom.c
472 */
473 void ide_packet_command( unsigned char *cmd )
474 {
475 uint32_t length;
476 uint32_t lba, status;
478 /* Okay we have the packet in the command buffer */
479 DEBUG( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
480 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
481 cmd[8], cmd[9], cmd[10], cmd[11] );
483 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
484 ide_set_packet_result( PKT_ERR_RESET );
485 idereg.was_reset = FALSE;
486 return;
487 }
489 switch( cmd[0] ) {
490 case PKT_CMD_TEST_READY:
491 REQUIRE_DISC();
492 ide_set_packet_result( 0 );
493 ide_raise_interrupt();
494 idereg.status = 0x50;
495 break;
496 case PKT_CMD_DRIVE_STATUS:
497 lba = cmd[2];
498 if( lba >= GDROM_DRIVE_STATUS_LENGTH ) {
499 ide_set_error(PKT_ERR_BADFIELD);
500 } else {
501 uint8_t status = ide_get_drive_status();
502 /* FIXME: Refactor read_position to avoid this kind of crud */
503 unsigned char tmp[16];
504 gdrom_read_short_status( idereg.current_lba, tmp );
506 length = cmd[4];
507 if( lba+length > GDROM_DRIVE_STATUS_LENGTH )
508 length = GDROM_DRIVE_STATUS_LENGTH - lba;
509 char data[10];
510 data[0] = status & 0x0F;
511 data[1] = status & 0xF0;
512 data[2] = tmp[4];
513 data[3] = tmp[5];
514 data[4] = tmp[6];
515 data[5] = tmp[11];
516 data[6] = tmp[12];
517 data[7] = tmp[13];
518 data[8] = 0;
519 data[9] = 0;
520 memcpy( data_buffer, data + lba, length );
521 ide_start_packet_read( length, 0 );
522 }
523 break;
524 case PKT_CMD_MODE_SENSE:
525 lba = cmd[2];
526 if( lba >= GDROM_MODE_LENGTH ) {
527 ide_set_error(PKT_ERR_BADFIELD);
528 } else {
529 length = cmd[4];
530 if( lba+length > GDROM_MODE_LENGTH )
531 length = GDROM_MODE_LENGTH - lba;
532 memcpy( data_buffer, idereg.gdrom_mode + lba, length );
533 ide_start_packet_read( length, 0 );
534 }
535 break;
536 case PKT_CMD_MODE_SELECT:
537 lba = cmd[2];
538 if( lba >= GDROM_MODE_LENGTH ) {
539 ide_set_error(PKT_ERR_BADFIELD);
540 } else {
541 length = cmd[4];
542 if( lba+length > GDROM_MODE_LENGTH )
543 length = GDROM_MODE_LENGTH - lba;
544 idereg.current_lba = lba;
545 ide_start_packet_write( length, 0 );
546 }
547 break;
548 case PKT_CMD_SENSE:
549 length = cmd[4];
550 if( length > 10 )
551 length = 10;
552 memcpy( data_buffer, idereg.gdrom_sense, length );
553 ide_start_packet_read( length, 0 );
554 break;
555 case PKT_CMD_READ_TOC:
556 length = (cmd[3]<<8) | cmd[4];
557 if( length > GDROM_TOC_SIZE )
558 length = GDROM_TOC_SIZE;
560 status = gdrom_read_toc( data_buffer );
561 if( status != PKT_ERR_OK ) {
562 ide_set_packet_result( status );
563 } else {
564 ide_start_packet_read( length, 0 );
565 }
566 break;
567 case PKT_CMD_SESSION_INFO:
568 length = cmd[4];
569 if( length > 6 )
570 length = 6;
571 status = gdrom_read_session( cmd[2], data_buffer );
572 if( status != PKT_ERR_OK ) {
573 ide_set_packet_result( status );
574 } else {
575 ide_start_packet_read( length, 0 );
576 }
577 break;
578 case PKT_CMD_PLAY_AUDIO:
579 lba = (cmd[2] << 16) | (cmd[3]<<8) | cmd[4];
580 length = ((cmd[8]<<16) | (cmd[9]<<8) | cmd[10]) - lba;
581 status = gdrom_play_audio( lba, length );
582 ide_set_packet_result( status );
583 ide_raise_interrupt();
584 idereg.status = 0x50;
585 break;
586 case PKT_CMD_READ_SECTOR:
587 REQUIRE_DISC();
588 idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
589 idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
590 idereg.current_mode = cmd[1];
591 ide_read_next_sector();
592 break;
593 case PKT_CMD_SPIN_UP:
594 REQUIRE_DISC();
595 /* do nothing? */
596 ide_set_packet_result( PKT_ERR_OK );
597 ide_raise_interrupt();
598 break;
599 case PKT_CMD_STATUS:
600 REQUIRE_DISC();
601 length = cmd[4];
602 switch( cmd[1] ) {
603 case 0:
604 if( length > sizeof(gdrom_status) ) {
605 length = sizeof(gdrom_status);
606 }
607 memcpy( data_buffer, gdrom_status, length );
608 ide_start_packet_read( length, 0 );
609 break;
610 case 1:
611 if( length > 14 ) {
612 length = 14;
613 }
614 gdrom_read_short_status( idereg.current_lba, data_buffer );
615 ide_start_packet_read( length, 0 );
616 break;
617 }
618 break;
619 case PKT_CMD_71:
620 /* This is a weird one. As far as I can tell it returns random garbage
621 * (and not even the same length each time, never mind the same data).
622 * For sake of something to do, it returns the results from a test dump
623 */
624 REQUIRE_DISC();
625 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
626 ide_start_packet_read( sizeof(gdrom_71), 0 );
627 break;
628 default:
629 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
630 return;
631 }
632 idereg.last_packet_command = cmd[0];
633 }
635 void ide_write_buffer( unsigned char *data, uint32_t length )
636 {
637 switch( idereg.last_packet_command ) {
638 case PKT_CMD_MODE_SELECT:
639 if( idereg.current_lba < 10 ) {
640 if( idereg.current_lba + length > 10 ) {
641 length = 10 - idereg.current_lba;
642 }
643 memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
644 }
645 break;
646 default:
647 WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
648 }
649 }
.