filename | src/gdrom/ide.c |
changeset | 256:8bac2f96ca1b |
prev | 254:7c9e34c37670 |
next | 258:8864fae65928 |
author | nkeynes |
date | Thu Dec 21 11:13:10 2006 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Put ide_raise_interrupt() back in after set feature - it's needed even tho the test case seemed to indicate that it didn't happen... |
view | annotate | diff | log | raw |
1 /**
2 * $Id: ide.c,v 1.21 2006-12-21 11:13:10 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 ide_raise_interrupt();
404 break;
405 default:
406 WARN( "IDE: Unimplemented command: %02X", val );
407 }
408 }
410 /**
411 * Execute a packet command. This particular method is responsible for parsing
412 * the command buffers (12 bytes), and generating the appropriate responses,
413 * although the actual implementation is mostly delegated to gdrom.c
414 */
415 void ide_packet_command( unsigned char *cmd )
416 {
417 uint32_t length, datalen;
418 uint32_t lba, status;
419 int mode;
420 int blocksize = idereg.lba1 + (idereg.lba2<<8);
422 /* Okay we have the packet in the command buffer */
423 INFO( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
424 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
425 cmd[8], cmd[9], cmd[10], cmd[11] );
427 if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
428 ide_set_packet_result( PKT_ERR_RESET );
429 idereg.was_reset = FALSE;
430 return;
431 }
433 switch( cmd[0] ) {
434 case PKT_CMD_TEST_READY:
435 if( !gdrom_is_mounted() ) {
436 ide_set_packet_result( PKT_ERR_NODISC );
437 } else {
438 ide_set_packet_result( 0 );
439 ide_raise_interrupt();
440 idereg.status = 0x50;
441 }
442 break;
443 case PKT_CMD_IDENTIFY:
444 lba = cmd[2];
445 if( lba >= sizeof(gdrom_ident) ) {
446 ide_set_error(PKT_ERR_BADFIELD);
447 } else {
448 length = cmd[4];
449 if( lba+length > sizeof(gdrom_ident) )
450 length = sizeof(gdrom_ident) - lba;
451 memcpy( data_buffer, gdrom_ident + lba, length );
452 ide_start_packet_read( length, blocksize );
453 }
454 break;
455 case PKT_CMD_SENSE:
456 length = cmd[4];
457 if( length > 10 )
458 length = 10;
459 memcpy( data_buffer, idereg.gdrom_sense, length );
460 ide_start_packet_read( length, blocksize );
461 break;
462 case PKT_CMD_READ_TOC:
463 length = (cmd[3]<<8) | cmd[4];
464 if( length > sizeof(struct gdrom_toc) )
465 length = sizeof(struct gdrom_toc);
467 status = gdrom_get_toc( data_buffer );
468 if( status != PKT_ERR_OK ) {
469 ide_set_packet_result( status );
470 } else {
471 ide_start_packet_read( length, blocksize );
472 }
473 break;
474 case PKT_CMD_SESSION_INFO:
475 length = cmd[4];
476 if( length > 6 )
477 length = 6;
478 status = gdrom_get_info( data_buffer, cmd[2] );
479 if( status != PKT_ERR_OK ) {
480 ide_set_packet_result( status );
481 } else {
482 ide_start_packet_read( length, blocksize );
483 }
484 break;
485 case PKT_CMD_PLAY_CD:
486 ide_set_packet_result( 0 );
487 ide_raise_interrupt();
488 idereg.status = 0x50;
489 break;
490 case PKT_CMD_READ_SECTOR:
491 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
492 length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
493 switch( cmd[1] ) {
494 case 0x20: mode = GDROM_MODE1; break; /* TODO - might be unchecked? */
495 case 0x24: mode = GDROM_GD; break;
496 case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
497 case 0x30: mode = GDROM_RAW; break;
498 default:
499 ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
500 ide_set_packet_result( PKT_ERR_BADFIELD );
501 return;
502 }
504 if( length > data_buffer_len ) {
505 do {
506 data_buffer_len = data_buffer_len << 1;
507 } while( data_buffer_len < length );
508 data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
509 }
511 datalen = data_buffer_len;
512 status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
513 if( status != 0 ) {
514 ide_set_packet_result( status );
515 idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
516 idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
517 idereg.gdrom_sense[7] = lba & 0xFF;
518 } else {
519 idereg.last_read_lba = lba + length;
520 idereg.last_read_track = gdrom_get_track_no_by_lba( idereg.last_read_lba );
521 ide_start_packet_read( datalen, blocksize );
522 }
523 break;
524 case PKT_CMD_SPIN_UP:
525 /* do nothing? */
526 ide_set_packet_result( PKT_ERR_OK );
527 ide_raise_interrupt();
528 break;
529 case PKT_CMD_STATUS:
530 length = cmd[4];
531 if( !gdrom_is_mounted() ) {
532 ide_set_packet_result( PKT_ERR_NODISC );
533 } else {
534 switch( cmd[1] ) {
535 case 0:
536 if( length > sizeof(gdrom_status) ) {
537 length = sizeof(gdrom_status);
538 }
539 memcpy( data_buffer, gdrom_status, length );
540 ide_start_packet_read( length, blocksize );
541 break;
542 case 1:
543 if( length > 14 ) {
544 length = 14;
545 }
546 gdrom_track_t track = gdrom_get_track(idereg.last_read_track);
547 int offset = idereg.last_read_lba - track->lba;
548 data_buffer[0] = 0x00;
549 data_buffer[1] = 0x15; /* ??? */
550 data_buffer[2] = 0x00;
551 data_buffer[3] = 0x0E;
552 data_buffer[4] = track->flags;
553 data_buffer[5] = idereg.last_read_track;
554 data_buffer[6] = 0x01; /* ?? */
555 data_buffer[7] = (offset >> 16) & 0xFF;
556 data_buffer[8] = (offset >> 8) & 0xFF;
557 data_buffer[9] = offset & 0xFF;
558 data_buffer[10] = (idereg.last_read_lba >> 24) & 0xFF;
559 data_buffer[11] = (idereg.last_read_lba >> 16) & 0xFF;
560 data_buffer[12] = (idereg.last_read_lba >> 8) & 0xFF;
561 data_buffer[13] = idereg.last_read_lba & 0xFF;
562 ide_start_packet_read( length, blocksize );
563 break;
564 }
565 }
566 break;
567 case PKT_CMD_71:
568 /* This is a weird one. As far as I can tell it returns random garbage
569 * (and not even the same length each time, never mind the same data).
570 * For sake of something to do, it returns the results from a test dump
571 */
572 memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
573 ide_start_packet_read( sizeof(gdrom_71), blocksize );
574 break;
575 default:
576 ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
577 return;
578 }
579 }
.