filename | src/gdrom/ide.c |
changeset | 254:7c9e34c37670 |
prev | 250:84e056e12a19 |
next | 256:8bac2f96ca1b |
author | nkeynes |
date | Thu Dec 21 10:15:54 2006 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Fix 0x40,0x01 in accordance with test results Add reset flag to fail first packet command (also as per tests) |
view | annotate | diff | log | raw |
1 /**
2 * $Id: ide.c,v 1.20 2006-12-21 10:15:54 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 };
61 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE, 0x1D, 0xD9, 0x89, 0x04, 0x28, 0x3A, 0x8E, 0x26, 0x5C, 0x95, 0x10, 0x5A,
62 0x0A, 0x99, 0xEE, 0xFB, 0x69, 0xCE, 0xD9, 0x63, 0x00, 0xF5, 0x0A, 0xBC, 0x2C, 0x0D, 0xF8, 0xE2,
63 0x05, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3D, 0x08, 0xD8, 0x8D, 0x08, 0x7A, 0x6D, 0x00, 0x35, 0x06,
64 0xBA, 0x66, 0x10, 0x00, 0x91, 0x08, 0x10, 0x29, 0xD0, 0x45, 0xDA, 0x00, 0x2D, 0x05, 0x69, 0x09,
65 0x00, 0x5E, 0x0F, 0x70, 0x86, 0x12, 0x6C, 0x77, 0x5A, 0xFB, 0xCD, 0x56, 0xFB, 0xF7, 0xB7, 0x00,
66 0x5D, 0x07, 0x19, 0x99, 0xF2, 0xAF, 0x00, 0x63, 0x03, 0x00, 0xF0, 0x10, 0xBE, 0xD7, 0xA0, 0x63,
67 0xFA, 0x84, 0xA7, 0x74, 0x94, 0xEF, 0xAD, 0xC2, 0xAC, 0x00, 0x78, 0x07, 0x9F, 0x57, 0x0B, 0x62,
68 0x00, 0xFE, 0x08, 0x08, 0x5D, 0x5A, 0x6A, 0x54, 0x00, 0xE2, 0x09, 0x93, 0x7E, 0x62, 0x2A, 0x5E,
69 0xDA, 0x00, 0x7E, 0x0F, 0xF0, 0x07, 0x01, 0x6D, 0x50, 0x86, 0xDD, 0x4A, 0x15, 0x54, 0xC7, 0xEC,
70 0x00, 0xF2, 0x0B, 0x07, 0xF8, 0x1A, 0xB0, 0x99, 0x3B, 0xF1, 0x36, 0x00, 0x94, 0x07, 0x34, 0xE3,
71 0xBC, 0x6E, 0x00, 0x34, 0x0D, 0x6F, 0xDA, 0xBD, 0xEE, 0xF7, 0xCC, 0xCE, 0x39, 0x7E, 0xE3, 0x00,
72 0x14, 0x08, 0xDC, 0xD2, 0xB9, 0xF9, 0x31, 0x00, 0xB0, 0x0C, 0x10, 0xA3, 0x45, 0x12, 0xC7, 0xCD,
73 0xBF, 0x05, 0x37, 0x00, 0xC4, 0x0D, 0x5F, 0xE0, 0x59, 0xBB, 0x01, 0x59, 0x03, 0xD6, 0x29, 0x9C,
74 0x00, 0x01, 0x0A, 0x09, 0xAA, 0xA8, 0xA8, 0x24, 0x0B, 0x66, 0x00, 0x5C, 0x05, 0xA5, 0xCE, 0x00,
75 0xC1, 0x0B, 0xB7, 0xA0, 0x6F, 0xE9, 0x2B, 0xCC, 0xB5, 0xFC, 0x00, 0x8D, 0x05, 0xF4, 0xAC, 0x00,
76 0x57, 0x04, 0xB6, 0x00, 0xFC, 0x03, 0x00, 0xC3, 0x10, 0x43, 0x3B, 0xBE, 0xA2, 0x96, 0xC3, 0x65,
77 0x9F, 0x9A, 0x88, 0xD5, 0x49, 0x68, 0x00, 0xDC, 0x11, 0x56, 0x23, 0x2D, 0xF9, 0xFC, 0xF5, 0x8B,
78 0x1B, 0xB1, 0xB7, 0x10, 0x21, 0x1C, 0x12, 0x00, 0x0D, 0x0D, 0xEB, 0x86, 0xA2, 0x49, 0x8D, 0x8D,
79 0xBE, 0xA1, 0x6D, 0x53, 0x00, 0xE1, 0x0A, 0x8E, 0x67, 0xAA, 0x16, 0x79, 0x39, 0x59, 0x00, 0x36,
80 0x0B, 0x2A, 0x4E, 0xAE, 0x51, 0x4B, 0xD0, 0x66, 0x33, 0x00, 0x8A, 0x07, 0xCD, 0x6F, 0xBA, 0x92,
81 0x00, 0x1A, 0x0E, 0xDF, 0x4A, 0xB3, 0x77, 0x1F, 0xA5, 0x90, 0x19, 0xFA, 0x59, 0xD7, 0x00, 0x04,
82 0x0F, 0xAC, 0xCA, 0x9F, 0xA4, 0xFC, 0x6D, 0x90, 0x86, 0x9E, 0x1F, 0x44, 0x40, 0x00, 0x9F, 0x04,
83 0x56, 0x00, 0x22, 0x03, 0x00, 0xB8, 0x10, 0x2C, 0x7A, 0x53, 0xA4, 0xBF, 0xA3, 0x90, 0x90, 0x14,
84 0x9D, 0x46, 0x6C, 0x96, 0x00, 0xC6, 0x0B, 0x9B, 0xBB, 0xB0, 0xAE, 0x60, 0x92, 0x8E, 0x0C, 0x00,
85 0x14, 0x06, 0x4B, 0xAE, 0x7F, 0x00, 0x5C, 0x0B, 0x23, 0xFA, 0xE7, 0x51, 0xDA, 0x61, 0x49, 0x5E,
86 0x00, 0xD7, 0x0B, 0x01, 0xFC, 0x55, 0x31, 0x84, 0xC5, 0x0C, 0x98, 0x00, 0x97, 0x50, 0x6E, 0xF9,
87 0xEE, 0x75, 0x92, 0x53, 0xD3, 0x66, 0xA4, 0xAF, 0x3B, 0xFE, 0x7B, 0x27, 0x30, 0xBB, 0xB6, 0xF2,
88 0x76, 0x22, 0x45, 0x42, 0xCA, 0xF9, 0xF0, 0xDE, 0x9F, 0x45, 0x16, 0x68, 0x22, 0xB9, 0x84, 0x28,
89 0x8F, 0x2B, 0xB5, 0x5C, 0xD2, 0xF5, 0x45, 0x36, 0x3E, 0x76, 0xC6, 0xBF, 0x32, 0x5C, 0x41, 0xA6,
90 0x26, 0xC7, 0x82, 0x2F, 0x2E, 0xB5, 0x75, 0xC6, 0xE6, 0x67, 0x9E, 0x77, 0x94, 0xAF, 0x6A, 0x05,
91 0xC0, 0x05, 0x61, 0x71, 0x89, 0x5A, 0xB1, 0xD0, 0xFC, 0x7E, 0xC0, 0x9B, 0xCB, 0x3B, 0x69, 0xD9,
92 0x5F, 0xAF, 0xCA, 0xAB, 0x25, 0xD5, 0xBE, 0x8A, 0x6B, 0xB0, 0xFB, 0x61, 0x6C, 0xEB, 0x85, 0x6E,
93 0x7A, 0x48, 0xFF, 0x97, 0x91, 0x06, 0x3D, 0x4D, 0x68, 0xD3, 0x65, 0x83, 0x90, 0xA0, 0x08, 0x5C,
94 0xFC, 0xEE, 0x7C, 0x33, 0x43, 0x7F, 0x80, 0x52, 0x8B, 0x19, 0x72, 0xF2, 0xC9, 0xAB, 0x93, 0xAF,
95 0x16, 0xED, 0x36, 0x48, 0xAB, 0xC9, 0xD1, 0x03, 0xB3, 0xDC, 0x2F, 0xF2, 0x92, 0x3F, 0x0A, 0x19,
96 0x25, 0xE2, 0xEF, 0x7A, 0x22, 0xDA, 0xDB, 0xCB, 0x32, 0x12, 0x61, 0x49, 0x5B, 0x74, 0x7C, 0x65,
97 0x20, 0x89, 0x54, 0x9E, 0x0E, 0xC9, 0x52, 0xE3, 0xC9, 0x9A, 0x44, 0xC9, 0x5D, 0xA6, 0x77, 0xC0,
98 0xE7, 0x60, 0x91, 0x80, 0x50, 0x1F, 0x33, 0xB1, 0xCD, 0xAD, 0xF4, 0x0D, 0xBB, 0x08, 0xB1, 0xD0,
99 0x13, 0x95, 0xAE, 0xC9, 0xE2, 0x64, 0xA2, 0x65, 0xFB, 0x8F, 0xE9, 0xA2, 0x8A, 0xBC, 0x98, 0x81,
100 0x45, 0xB4, 0x55, 0x4E, 0xB9, 0x74, 0xB4, 0x50, 0x76, 0xBF, 0xF0, 0x45, 0xE7, 0xEE, 0x41, 0x64,
101 0x9F, 0xB5, 0xE0, 0xBB, 0x1C, 0xBB, 0x28, 0x66, 0x1B, 0xDD, 0x2B, 0x02, 0x66, 0xBF, 0xFD, 0x7D,
102 0x37, 0x35, 0x1D, 0x76, 0x21, 0xC3, 0x8F, 0xAF, 0xF6, 0xF9, 0xE9, 0x27, 0x48, 0xE7, 0x3D, 0x95,
103 0x74, 0x0C, 0x77, 0x88, 0x56, 0xD9, 0x84, 0xC8, 0x7D, 0x20, 0x31, 0x43, 0x53, 0xF1, 0xC1, 0xC7,
104 0xC9, 0xF7, 0x5C, 0xC0, 0xA6, 0x5A, 0x27, 0x0A, 0x41, 0xD4, 0x44, 0x94, 0x65, 0x4F, 0xE2, 0x53,
105 0x60, 0x0B, 0xD1, 0x23, 0x6C, 0x0C, 0xBC, 0x70, 0x6C, 0x26, 0x1A, 0x61, 0x1D, 0x35, 0x88, 0xEC,
106 0xB8, 0x15, 0xE3, 0xB4, 0x82, 0xEE, 0xB3, 0x21, 0xAC, 0x6C, 0xB7, 0x33, 0x6D, 0x78, 0x0C, 0x0D,
107 0xB4, 0x0B, 0x29, 0xF2, 0xD4, 0x8C, 0x3F, 0xDD, 0x3F, 0x47, 0xDD, 0xF2, 0xD8, 0x39, 0x57, 0x20,
108 0x28, 0xD8, 0xDD, 0x32, 0xE2, 0x6A, 0x47, 0x53, 0x57, 0xC6, 0xFA, 0x7A, 0x38, 0x30, 0x31, 0x8F,
109 0xE7, 0xD3, 0x84, 0x2B, 0x5D, 0x4F, 0x95, 0x98, 0xED, 0x0B, 0xD7, 0x50, 0x0C, 0x49, 0xDA, 0x59,
110 0x15, 0xF1, 0x39, 0xF3, 0x40, 0xDC, 0xDC, 0x25, 0x24, 0x56, 0x6E, 0xA9, 0x2F, 0xF0, 0x00, 0x00 };
113 char gdrom_status[] = {
114 0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
120 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
123 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
124 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
125 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
126 0x00, 0x40, 0x00, 0x00 };
129 static void ide_init( void )
130 {
131 ide_reset();
132 data_buffer_len = DEFAULT_DATA_SECTORS;
133 data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len );
134 assert( data_buffer != NULL );
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.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
149 idereg.state = IDE_STATE_IDLE;
150 memset( idereg.gdrom_sense, '\0', 10 );
151 idereg.data_offset = -1;
152 idereg.data_length = -1;
153 idereg.last_read_track = 1;
154 idereg.last_read_lba = 150;
155 idereg.was_reset = TRUE;
156 }
158 static void ide_save_state( FILE *f )
159 {
160 fwrite( &idereg, sizeof(idereg), 1, f );
161 fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
162 fwrite( data_buffer, MAX_SECTOR_SIZE, data_buffer_len, f );
163 }
165 static int ide_load_state( FILE *f )
166 {
167 uint32_t length;
168 fread( &idereg, sizeof(idereg), 1, f );
169 fread( &length, sizeof(uint32_t), 1, f );
170 if( length > data_buffer_len ) {
171 if( data_buffer != NULL )
172 free( data_buffer );
173 data_buffer = malloc( MAX_SECTOR_SIZE * length );
174 assert( data_buffer != NULL );
175 data_buffer_len = length;
176 }
177 fread( data_buffer, MAX_SECTOR_SIZE, length, f );
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 ide_raise_interrupt();
193 } else {
194 idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
195 }
196 }
198 /**
199 * Begin command packet write to the device. This is always 12 bytes of PIO data
200 */
201 static void ide_start_command_packet_write( )
202 {
203 idereg.state = IDE_STATE_CMD_WRITE;
204 idereg.status = 0x58;
205 idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
206 idereg.count = IDE_COUNT_CD;
207 idereg.data_offset = 0;
208 idereg.data_length = 12;
209 }
211 /**
212 * Begin PIO read from the device. The data is assumed to already be
213 * in the buffer at this point.
214 */
215 static void ide_start_read( int length, int blocksize, gboolean dma )
216 {
217 idereg.count = IDE_COUNT_IO;
218 idereg.data_length = length;
219 idereg.data_offset = 0;
220 if( dma ) {
221 idereg.state = IDE_STATE_DMA_READ;
222 idereg.status = 0xD0;
223 } else {
224 idereg.state = IDE_STATE_PIO_READ;
225 idereg.status = 0x58;
226 idereg.lba1 = length & 0xFF;
227 idereg.lba2 = (length >> 8) & 0xFF;
228 // idereg.lba1 = blocksize & 0xFF;
229 // idereg.lba2 = blocksize >> 8;
230 idereg.block_length = blocksize;
231 idereg.block_left = blocksize;
232 ide_raise_interrupt( );
233 }
234 }
236 static void ide_start_packet_read( int length, int blocksize )
237 {
238 ide_set_packet_result( PKT_ERR_OK );
239 ide_start_read( length, blocksize, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
240 }
242 static void ide_raise_interrupt( void )
243 {
244 if( idereg.intrq_pending == 0 ) {
245 idereg.intrq_pending = 1;
246 if( IS_IDE_IRQ_ENABLED() )
247 asic_event( EVENT_IDE );
248 }
249 }
251 static void ide_clear_interrupt( void )
252 {
253 if( idereg.intrq_pending != 0 ) {
254 idereg.intrq_pending = 0;
255 if( IS_IDE_IRQ_ENABLED() )
256 asic_clear_event( EVENT_IDE );
257 }
258 }
260 static void ide_set_error( int error_code )
261 {
262 idereg.status = 0x51;
263 idereg.error = error_code;
264 }
266 uint8_t ide_read_status( void )
267 {
268 if( (idereg.status & IDE_STATUS_BSY) == 0 )
269 ide_clear_interrupt();
270 return idereg.status;
271 }
273 uint16_t ide_read_data_pio( void ) {
274 if( idereg.state == IDE_STATE_PIO_READ ) {
275 uint16_t rv = READ_BUFFER();
276 idereg.data_offset += 2;
277 idereg.block_left -= 2;
278 if( idereg.data_offset >= idereg.data_length ) {
279 idereg.state = IDE_STATE_IDLE;
280 idereg.status &= ~IDE_STATUS_DRQ;
281 idereg.data_offset = -1;
282 idereg.count = 3; /* complete */
283 ide_raise_interrupt();
284 } else if( idereg.block_left <= 0 ) {
285 idereg.block_left = idereg.block_length;
286 ide_raise_interrupt();
287 }
288 return rv;
289 } else {
290 return 0xFFFF;
291 }
292 }
295 /**
296 * DMA read request
297 *
298 * This method is called from the ASIC side when a DMA read request is
299 * initiated. If there is a pending DMA transfer already, we copy the
300 * data immediately, otherwise we record the DMA buffer for use when we
301 * get to actually doing the transfer.
302 * @return number of bytes transfered
303 */
304 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
305 {
306 if( idereg.state == IDE_STATE_DMA_READ ) {
307 int xferlen = length;
308 int remaining = idereg.data_length - idereg.data_offset;
309 if( xferlen > remaining )
310 xferlen = remaining;
311 mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
312 idereg.data_offset += xferlen;
313 if( idereg.data_offset >= idereg.data_length ) {
314 idereg.data_offset = -1;
315 idereg.state = IDE_STATE_IDLE;
316 idereg.status = 0x50;
317 idereg.count = 0x03;
318 ide_raise_interrupt();
319 asic_event( EVENT_IDE_DMA );
320 }
321 return xferlen;
322 }
323 return 0;
324 }
326 void ide_write_data_pio( uint16_t val ) {
327 if( idereg.state == IDE_STATE_CMD_WRITE ) {
328 WRITE_BUFFER(val);
329 idereg.data_offset+=2;
330 if( idereg.data_offset >= idereg.data_length ) {
331 idereg.state = IDE_STATE_BUSY;
332 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
333 idereg.data_offset = -1;
334 ide_packet_command(data_buffer);
335 }
336 } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
337 WRITE_BUFFER(val);
338 if( idereg.data_offset >= idereg.data_length ) {
339 idereg.state = IDE_STATE_BUSY;
340 idereg.data_offset = -1;
341 idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
342 /* ??? - no data writes yet anyway */
343 }
344 }
345 }
347 void ide_write_control( uint8_t val ) {
348 if( IS_IDE_IRQ_ENABLED() ) {
349 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
350 asic_clear_event( EVENT_IDE );
351 } else {
352 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
353 asic_event( EVENT_IDE );
354 }
355 idereg.control = val;
356 }
358 void ide_write_command( uint8_t val ) {
359 ide_clear_interrupt();
360 idereg.command = val;
361 switch( val ) {
362 case IDE_CMD_NOP: /* Effectively an "abort" */
363 idereg.state = IDE_STATE_IDLE;
364 idereg.status = 0x51;
365 idereg.error = 0x04;
366 idereg.data_offset = -1;
367 ide_raise_interrupt();
368 return;
369 case IDE_CMD_RESET_DEVICE:
370 ide_reset();
371 break;
372 case IDE_CMD_PACKET:
373 ide_start_command_packet_write();
374 break;
375 case IDE_CMD_SET_FEATURE:
376 switch( idereg.feature ) {
377 case IDE_FEAT_SET_TRANSFER_MODE:
378 switch( idereg.count & 0xF8 ) {
379 case IDE_XFER_PIO:
380 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
381 break;
382 case IDE_XFER_PIO_FLOW:
383 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
384 break;
385 case IDE_XFER_MULTI_DMA:
386 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
387 break;
388 case IDE_XFER_ULTRA_DMA:
389 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
390 break;
391 default:
392 INFO( "Setting unknown transfer mode: %02X", idereg.count );
393 break;
394 }
395 break;
396 default:
397 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
398 }
399 idereg.status = 0x50;
400 idereg.error = 0x00;
401 idereg.lba1 = 0x00;
402 idereg.lba2 = 0x00;
403 break;
404 default:
405 WARN( "IDE: Unimplemented command: %02X", val );
406 }
407 }
409 /**
410 * Execute a packet command. This particular method is responsible for parsing
411 * the command buffers (12 bytes), and generating the appropriate responses,
412 * although the actual implementation is mostly delegated to gdrom.c
413 */
414 void ide_packet_command( unsigned char *cmd )
415 {
416 uint32_t length, datalen;
417 uint32_t lba, status;
418 int mode;
419 int blocksize = idereg.lba1 + (idereg.lba2<<8);
421 /* Okay we have the packet in the command buffer */
422 INFO( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
423 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
424 cmd[8], cmd[9], cmd[10], cmd[11] );
426 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
427 ide_set_packet_result( PKT_ERR_RESET );
428 idereg.was_reset = FALSE;
429 return;
430 }
432 switch( cmd[0] ) {
433 case PKT_CMD_TEST_READY:
434 if( !gdrom_is_mounted() ) {
435 ide_set_packet_result( PKT_ERR_NODISC );
436 } else {
437 ide_set_packet_result( 0 );
438 ide_raise_interrupt();
439 idereg.status = 0x50;
440 }
441 break;
442 case PKT_CMD_IDENTIFY:
443 lba = cmd[2];
444 if( lba >= sizeof(gdrom_ident) ) {
445 ide_set_error(PKT_ERR_BADFIELD);
446 } else {
447 length = cmd[4];
448 if( lba+length > sizeof(gdrom_ident) )
449 length = sizeof(gdrom_ident) - lba;
450 memcpy( data_buffer, gdrom_ident + lba, length );
451 ide_start_packet_read( length, blocksize );
452 }
453 break;
454 case PKT_CMD_SENSE:
455 length = cmd[4];
456 if( length > 10 )
457 length = 10;
458 memcpy( data_buffer, idereg.gdrom_sense, length );
459 ide_start_packet_read( length, blocksize );
460 break;
461 case PKT_CMD_READ_TOC:
462 length = (cmd[3]<<8) | cmd[4];
463 if( length > sizeof(struct gdrom_toc) )
464 length = sizeof(struct gdrom_toc);
466 status = gdrom_get_toc( data_buffer );
467 if( status != PKT_ERR_OK ) {
468 ide_set_packet_result( status );
469 } else {
470 ide_start_packet_read( length, blocksize );
471 }
472 break;
473 case PKT_CMD_SESSION_INFO:
474 length = cmd[4];
475 if( length > 6 )
476 length = 6;
477 status = gdrom_get_info( data_buffer, cmd[2] );
478 if( status != PKT_ERR_OK ) {
479 ide_set_packet_result( status );
480 } else {
481 ide_start_packet_read( length, blocksize );
482 }
483 break;
484 case PKT_CMD_PLAY_CD:
485 ide_set_packet_result( 0 );
486 ide_raise_interrupt();
487 idereg.status = 0x50;
488 break;
489 case PKT_CMD_READ_SECTOR:
490 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
491 length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
492 switch( cmd[1] ) {
493 case 0x20: mode = GDROM_MODE1; break; /* TODO - might be unchecked? */
494 case 0x24: mode = GDROM_GD; break;
495 case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
496 case 0x30: mode = GDROM_RAW; break;
497 default:
498 ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
499 ide_set_packet_result( PKT_ERR_BADFIELD );
500 return;
501 }
503 if( length > data_buffer_len ) {
504 do {
505 data_buffer_len = data_buffer_len << 1;
506 } while( data_buffer_len < length );
507 data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
508 }
510 datalen = data_buffer_len;
511 status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
512 if( status != 0 ) {
513 ide_set_packet_result( status );
514 idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
515 idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
516 idereg.gdrom_sense[7] = lba & 0xFF;
517 } else {
518 idereg.last_read_lba = lba + length;
519 idereg.last_read_track = gdrom_get_track_no_by_lba( idereg.last_read_lba );
520 ide_start_packet_read( datalen, blocksize );
521 }
522 break;
523 case PKT_CMD_SPIN_UP:
524 /* do nothing? */
525 ide_set_packet_result( PKT_ERR_OK );
526 ide_raise_interrupt();
527 break;
528 case PKT_CMD_STATUS:
529 length = cmd[4];
530 if( !gdrom_is_mounted() ) {
531 ide_set_packet_result( PKT_ERR_NODISC );
532 } else {
533 switch( cmd[1] ) {
534 case 0:
535 if( length > sizeof(gdrom_status) ) {
536 length = sizeof(gdrom_status);
537 }
538 memcpy( data_buffer, gdrom_status, length );
539 ide_start_packet_read( length, blocksize );
540 break;
541 case 1:
542 if( length > 14 ) {
543 length = 14;
544 }
545 gdrom_track_t track = gdrom_get_track(idereg.last_read_track);
546 int offset = idereg.last_read_lba - track->lba;
547 data_buffer[0] = 0x00;
548 data_buffer[1] = 0x15; /* ??? */
549 data_buffer[2] = 0x00;
550 data_buffer[3] = 0x0E;
551 data_buffer[4] = track->flags;
552 data_buffer[5] = idereg.last_read_track;
553 data_buffer[6] = 0x01; /* ?? */
554 data_buffer[7] = (offset >> 16) & 0xFF;
555 data_buffer[8] = (offset >> 8) & 0xFF;
556 data_buffer[9] = offset & 0xFF;
557 data_buffer[10] = (idereg.last_read_lba >> 24) & 0xFF;
558 data_buffer[11] = (idereg.last_read_lba >> 16) & 0xFF;
559 data_buffer[12] = (idereg.last_read_lba >> 8) & 0xFF;
560 data_buffer[13] = idereg.last_read_lba & 0xFF;
561 ide_start_packet_read( length, blocksize );
562 break;
563 }
564 }
565 break;
566 case PKT_CMD_71:
567 /* This is a weird one. As far as I can tell it returns random garbage
568 * (and not even the same length each time, never mind the same data).
569 * For sake of something to do, it returns the results from a test dump
570 */
571 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
572 ide_start_packet_read( sizeof(gdrom_71), blocksize );
573 break;
574 default:
575 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
576 return;
577 }
578 }
.