filename | src/gdrom/ide.c |
changeset | 678:35eb00945316 |
prev | 629:2811e8a2debf |
next | 736:a02d1475ccfd |
author | nkeynes |
date | Thu May 29 11:00:26 2008 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Split gdrom.h into public and private gddriver.h Reorganize gdrom mount to use a disc change hook |
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 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 idereg.state = IDE_STATE_IDLE;
194 ide_raise_interrupt();
195 } else {
196 idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
197 }
198 }
200 /**
201 * Begin command packet write to the device. This is always 12 bytes of PIO data
202 */
203 static void ide_start_command_packet_write( )
204 {
205 idereg.state = IDE_STATE_CMD_WRITE;
206 idereg.status = 0x58;
207 idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
208 idereg.count = IDE_COUNT_CD;
209 idereg.data_offset = 0;
210 idereg.data_length = 12;
211 }
213 /**
214 * Begin PIO/DMA read from the device. The data is assumed to already be
215 * in the buffer at this point.
216 */
217 static void ide_start_read( int length, gboolean dma )
218 {
219 idereg.count = IDE_COUNT_IO;
220 idereg.data_length = length;
221 idereg.data_offset = 0;
222 if( dma ) {
223 idereg.state = IDE_STATE_DMA_READ;
224 idereg.status = 0xD0;
225 } else {
226 idereg.state = IDE_STATE_PIO_READ;
227 idereg.status = 0x58;
228 idereg.lba1 = length & 0xFF;
229 idereg.lba2 = length >> 8;
230 ide_raise_interrupt( );
231 }
232 }
234 static void ide_start_write( int length, gboolean dma )
235 {
236 idereg.count = 0;
237 idereg.data_length = length;
238 idereg.data_offset = 0;
239 if( dma ) {
240 idereg.state = IDE_STATE_DMA_WRITE;
241 idereg.status = 0xD0;
242 } else {
243 idereg.state = IDE_STATE_PIO_WRITE;
244 idereg.status = 0x58;
245 idereg.lba1 = length & 0xFF;
246 idereg.lba2 = length >> 8;
247 ide_raise_interrupt( );
248 }
249 }
251 static void ide_start_packet_read( int length, int sector_count )
252 {
253 idereg.sectors_left = sector_count;
254 ide_set_packet_result( PKT_ERR_OK );
255 ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
256 }
258 static void ide_start_packet_write( int length, int sector_count )
259 {
260 idereg.sectors_left = sector_count;
261 ide_set_packet_result( PKT_ERR_OK );
262 ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
263 }
265 static void ide_raise_interrupt( void )
266 {
267 if( idereg.intrq_pending == 0 ) {
268 idereg.intrq_pending = 1;
269 if( IS_IDE_IRQ_ENABLED() )
270 asic_event( EVENT_IDE );
271 }
272 }
274 static void ide_clear_interrupt( void )
275 {
276 if( idereg.intrq_pending != 0 ) {
277 idereg.intrq_pending = 0;
278 if( IS_IDE_IRQ_ENABLED() )
279 asic_clear_event( EVENT_IDE );
280 }
281 }
283 static void ide_set_error( int error_code )
284 {
285 idereg.status = 0x51;
286 idereg.error = error_code;
287 }
289 uint8_t ide_read_status( void )
290 {
291 if( (idereg.status & IDE_STATUS_BSY) == 0 )
292 ide_clear_interrupt();
293 return idereg.status;
294 }
296 uint16_t ide_read_data_pio( void ) {
297 if( idereg.state == IDE_STATE_PIO_READ ) {
298 uint16_t rv = READ_BUFFER();
299 idereg.data_offset += 2;
300 if( idereg.data_offset >= idereg.data_length ) {
301 idereg.state = IDE_STATE_IDLE;
302 idereg.status &= ~IDE_STATUS_DRQ;
303 idereg.data_offset = -1;
304 idereg.count = 3; /* complete */
305 ide_raise_interrupt();
306 if( idereg.sectors_left > 0 ) {
307 ide_read_next_sector();
308 }
309 }
310 return rv;
311 } else {
312 return 0xFFFF;
313 }
314 }
317 /**
318 * DMA read request
319 *
320 * This method is called from the ASIC side when a DMA read request is
321 * initiated. If there is a pending DMA transfer already, we copy the
322 * data immediately, otherwise we record the DMA buffer for use when we
323 * get to actually doing the transfer.
324 * @return number of bytes transfered
325 */
326 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
327 {
328 uint32_t xfercount = 0;
329 while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
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 return xfercount;
354 }
356 void ide_write_data_pio( uint16_t val ) {
357 if( idereg.state == IDE_STATE_CMD_WRITE ) {
358 WRITE_BUFFER(val);
359 idereg.data_offset+=2;
360 if( idereg.data_offset >= idereg.data_length ) {
361 idereg.state = IDE_STATE_BUSY;
362 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
363 idereg.data_offset = -1;
364 ide_packet_command(data_buffer);
365 }
366 } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
367 WRITE_BUFFER(val);
368 idereg.data_offset +=2;
369 if( idereg.data_offset >= idereg.data_length ) {
370 idereg.state = IDE_STATE_IDLE;
371 idereg.status &= ~IDE_STATUS_DRQ;
372 idereg.data_offset = -1;
373 idereg.count = 3; /* complete */
374 ide_raise_interrupt();
375 ide_write_buffer( data_buffer, idereg.data_length );
376 }
377 }
378 }
380 void ide_write_control( uint8_t val ) {
381 if( IS_IDE_IRQ_ENABLED() ) {
382 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
383 asic_clear_event( EVENT_IDE );
384 } else {
385 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
386 asic_event( EVENT_IDE );
387 }
388 idereg.control = val;
389 }
391 void ide_write_command( uint8_t val ) {
392 ide_clear_interrupt();
393 idereg.command = val;
394 switch( val ) {
395 case IDE_CMD_NOP: /* Effectively an "abort" */
396 idereg.state = IDE_STATE_IDLE;
397 idereg.status = 0x51;
398 idereg.error = 0x04;
399 idereg.data_offset = -1;
400 ide_raise_interrupt();
401 return;
402 case IDE_CMD_RESET_DEVICE:
403 ide_reset();
404 break;
405 case IDE_CMD_PACKET:
406 ide_start_command_packet_write();
407 break;
408 case IDE_CMD_SET_FEATURE:
409 switch( idereg.feature ) {
410 case IDE_FEAT_SET_TRANSFER_MODE:
411 switch( idereg.count & 0xF8 ) {
412 case IDE_XFER_PIO:
413 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
414 break;
415 case IDE_XFER_PIO_FLOW:
416 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
417 break;
418 case IDE_XFER_MULTI_DMA:
419 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
420 break;
421 case IDE_XFER_ULTRA_DMA:
422 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
423 break;
424 default:
425 INFO( "Setting unknown transfer mode: %02X", idereg.count );
426 break;
427 }
428 break;
429 default:
430 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
431 }
432 idereg.status = 0x50;
433 idereg.error = 0x00;
434 idereg.lba1 = 0x00;
435 idereg.lba2 = 0x00;
436 ide_raise_interrupt();
437 break;
438 default:
439 WARN( "IDE: Unimplemented command: %02X", val );
440 }
441 }
443 uint8_t ide_get_drive_status( void )
444 {
445 if( gdrom_disc == NULL ) {
446 return IDE_DISC_NONE;
447 } else {
448 return gdrom_disc->drive_status(gdrom_disc);
449 }
450 }
452 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
454 /**
455 * Read the next sector from the active read, if any
456 */
457 static void ide_read_next_sector( void )
458 {
459 uint32_t sector_size;
460 REQUIRE_DISC();
461 gdrom_error_t status =
462 gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode,
463 data_buffer, §or_size );
464 if( status != PKT_ERR_OK ) {
465 ide_set_packet_result( status );
466 idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
467 idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
468 idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
469 WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
470 } else {
471 idereg.current_lba++;
472 idereg.sectors_left--;
473 ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
474 }
475 }
477 /**
478 * Execute a packet command. This particular method is responsible for parsing
479 * the command buffers (12 bytes), and generating the appropriate responses,
480 * although the actual implementation is mostly delegated to gdrom.c
481 */
482 void ide_packet_command( unsigned char *cmd )
483 {
484 uint32_t length;
485 uint32_t lba, status;
487 /* Okay we have the packet in the command buffer */
488 INFO( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
489 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
490 cmd[8], cmd[9], cmd[10], cmd[11] );
492 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
493 ide_set_packet_result( PKT_ERR_RESET );
494 idereg.was_reset = FALSE;
495 return;
496 }
498 switch( cmd[0] ) {
499 case PKT_CMD_TEST_READY:
500 REQUIRE_DISC();
501 ide_set_packet_result( 0 );
502 ide_raise_interrupt();
503 idereg.status = 0x50;
504 break;
505 case PKT_CMD_MODE_SENSE:
506 lba = cmd[2];
507 if( lba >= GDROM_MODE_LENGTH ) {
508 ide_set_error(PKT_ERR_BADFIELD);
509 } else {
510 length = cmd[4];
511 if( lba+length > GDROM_MODE_LENGTH )
512 length = GDROM_MODE_LENGTH - lba;
513 memcpy( data_buffer, idereg.gdrom_mode + lba, length );
514 ide_start_packet_read( length, 0 );
515 }
516 break;
517 case PKT_CMD_MODE_SELECT:
518 lba = cmd[2];
519 if( lba >= GDROM_MODE_LENGTH ) {
520 ide_set_error(PKT_ERR_BADFIELD);
521 } else {
522 length = cmd[4];
523 if( lba+length > GDROM_MODE_LENGTH )
524 length = GDROM_MODE_LENGTH - lba;
525 idereg.current_lba = lba;
526 ide_start_packet_write( length, 0 );
527 }
528 break;
529 case PKT_CMD_SENSE:
530 length = cmd[4];
531 if( length > 10 )
532 length = 10;
533 memcpy( data_buffer, idereg.gdrom_sense, length );
534 ide_start_packet_read( length, 0 );
535 break;
536 case PKT_CMD_READ_TOC:
537 REQUIRE_DISC();
538 length = (cmd[3]<<8) | cmd[4];
539 if( length > sizeof(struct gdrom_toc) )
540 length = sizeof(struct gdrom_toc);
542 status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
543 if( status != PKT_ERR_OK ) {
544 ide_set_packet_result( status );
545 } else {
546 ide_start_packet_read( length, 0 );
547 }
548 break;
549 case PKT_CMD_SESSION_INFO:
550 REQUIRE_DISC();
551 length = cmd[4];
552 if( length > 6 )
553 length = 6;
554 status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
555 if( status != PKT_ERR_OK ) {
556 ide_set_packet_result( status );
557 } else {
558 ide_start_packet_read( length, 0 );
559 }
560 break;
561 case PKT_CMD_PLAY_AUDIO:
562 REQUIRE_DISC();
563 ide_set_packet_result( 0 );
564 ide_raise_interrupt();
565 idereg.status = 0x50;
566 break;
567 case PKT_CMD_READ_SECTOR:
568 REQUIRE_DISC();
569 idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
570 idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
571 idereg.current_mode = cmd[1];
572 ide_read_next_sector();
573 break;
574 case PKT_CMD_SPIN_UP:
575 REQUIRE_DISC();
576 /* do nothing? */
577 ide_set_packet_result( PKT_ERR_OK );
578 ide_raise_interrupt();
579 break;
580 case PKT_CMD_STATUS:
581 REQUIRE_DISC();
582 length = cmd[4];
583 switch( cmd[1] ) {
584 case 0:
585 if( length > sizeof(gdrom_status) ) {
586 length = sizeof(gdrom_status);
587 }
588 memcpy( data_buffer, gdrom_status, length );
589 ide_start_packet_read( length, 0 );
590 break;
591 case 1:
592 if( length > 14 ) {
593 length = 14;
594 }
595 gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
596 data_buffer[0] = 0x00;
597 data_buffer[1] = 0x15; /* audio status ? */
598 data_buffer[2] = 0x00;
599 data_buffer[3] = 0x0E;
600 ide_start_packet_read( length, 0 );
601 break;
602 }
603 break;
604 case PKT_CMD_71:
605 /* This is a weird one. As far as I can tell it returns random garbage
606 * (and not even the same length each time, never mind the same data).
607 * For sake of something to do, it returns the results from a test dump
608 */
609 REQUIRE_DISC();
610 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
611 ide_start_packet_read( sizeof(gdrom_71), 0 );
612 break;
613 default:
614 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
615 return;
616 }
617 idereg.last_packet_command = cmd[0];
618 }
620 void ide_write_buffer( unsigned char *data, uint32_t length )
621 {
622 switch( idereg.last_packet_command ) {
623 case PKT_CMD_MODE_SELECT:
624 if( idereg.current_lba < 10 ) {
625 if( idereg.current_lba + length > 10 ) {
626 length = 10 - idereg.current_lba;
627 }
628 memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
629 }
630 break;
631 default:
632 WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
633 }
634 }
.