75 |
#define SEQ_0 0x0 |
#define SEQ_0 0x0 |
76 |
#define SEQ_CD 0x4 |
#define SEQ_CD 0x4 |
77 |
|
|
78 |
|
/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ |
79 |
|
static void lba_to_msf(uint8_t *buf, int lba) |
80 |
|
{ |
81 |
|
lba += 150; |
82 |
|
buf[0] = (lba / 75) / 60; |
83 |
|
buf[1] = (lba / 75) % 60; |
84 |
|
buf[2] = lba % 75; |
85 |
|
} |
86 |
|
|
87 |
|
static inline void cpu_to_ube16(uint8_t *buf, int val) |
88 |
|
{ |
89 |
|
buf[0] = val >> 8; |
90 |
|
buf[1] = val; |
91 |
|
} |
92 |
|
|
93 |
|
static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) |
94 |
|
{ |
95 |
|
buf[0] = val >> 24; |
96 |
|
buf[1] = val >> 16; |
97 |
|
buf[2] = val >> 8; |
98 |
|
buf[3] = val; |
99 |
|
} |
100 |
|
|
101 |
|
/* same toc as bochs. Return -1 if error or the toc length */ |
102 |
|
/* XXX: check this */ |
103 |
|
static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) |
104 |
|
{ |
105 |
|
uint8_t *q; |
106 |
|
int len; |
107 |
|
|
108 |
|
if (start_track > 1 && start_track != 0xaa) |
109 |
|
return -1; |
110 |
|
q = buf + 2; |
111 |
|
*q++ = 1; /* first session */ |
112 |
|
*q++ = 1; /* last session */ |
113 |
|
if (start_track <= 1) { |
114 |
|
*q++ = 0; /* reserved */ |
115 |
|
*q++ = 0x14; /* ADR, control */ |
116 |
|
*q++ = 1; /* track number */ |
117 |
|
*q++ = 0; /* reserved */ |
118 |
|
if (msf) { |
119 |
|
*q++ = 0; /* reserved */ |
120 |
|
lba_to_msf(q, 0); |
121 |
|
q += 3; |
122 |
|
} else { |
123 |
|
/* sector 0 */ |
124 |
|
cpu_to_ube32(q, 0); |
125 |
|
q += 4; |
126 |
|
} |
127 |
|
} |
128 |
|
/* lead out track */ |
129 |
|
*q++ = 0; /* reserved */ |
130 |
|
*q++ = 0x16; /* ADR, control */ |
131 |
|
*q++ = 0xaa; /* track number */ |
132 |
|
*q++ = 0; /* reserved */ |
133 |
|
if (msf) { |
134 |
|
*q++ = 0; /* reserved */ |
135 |
|
lba_to_msf(q, nb_sectors); |
136 |
|
q += 3; |
137 |
|
} else { |
138 |
|
cpu_to_ube32(q, nb_sectors); |
139 |
|
q += 4; |
140 |
|
} |
141 |
|
len = q - buf; |
142 |
|
cpu_to_ube16(buf, len - 2); |
143 |
|
return len; |
144 |
|
} |
145 |
|
|
146 |
|
/* mostly same info as PearPc */ |
147 |
|
static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, |
148 |
|
int session_num) |
149 |
|
{ |
150 |
|
uint8_t *q; |
151 |
|
int len; |
152 |
|
|
153 |
|
q = buf + 2; |
154 |
|
*q++ = 1; /* first session */ |
155 |
|
*q++ = 1; /* last session */ |
156 |
|
|
157 |
|
*q++ = 1; /* session number */ |
158 |
|
*q++ = 0x14; /* data track */ |
159 |
|
*q++ = 0; /* track number */ |
160 |
|
*q++ = 0xa0; /* lead-in */ |
161 |
|
*q++ = 0; /* min */ |
162 |
|
*q++ = 0; /* sec */ |
163 |
|
*q++ = 0; /* frame */ |
164 |
|
*q++ = 0; |
165 |
|
*q++ = 1; /* first track */ |
166 |
|
*q++ = 0x00; /* disk type */ |
167 |
|
*q++ = 0x00; |
168 |
|
|
169 |
|
*q++ = 1; /* session number */ |
170 |
|
*q++ = 0x14; /* data track */ |
171 |
|
*q++ = 0; /* track number */ |
172 |
|
*q++ = 0xa1; |
173 |
|
*q++ = 0; /* min */ |
174 |
|
*q++ = 0; /* sec */ |
175 |
|
*q++ = 0; /* frame */ |
176 |
|
*q++ = 0; |
177 |
|
*q++ = 1; /* last track */ |
178 |
|
*q++ = 0x00; |
179 |
|
*q++ = 0x00; |
180 |
|
|
181 |
|
*q++ = 1; /* session number */ |
182 |
|
*q++ = 0x14; /* data track */ |
183 |
|
*q++ = 0; /* track number */ |
184 |
|
*q++ = 0xa2; /* lead-out */ |
185 |
|
*q++ = 0; /* min */ |
186 |
|
*q++ = 0; /* sec */ |
187 |
|
*q++ = 0; /* frame */ |
188 |
|
if (msf) { |
189 |
|
*q++ = 0; /* reserved */ |
190 |
|
lba_to_msf(q, nb_sectors); |
191 |
|
q += 3; |
192 |
|
} else { |
193 |
|
cpu_to_ube32(q, nb_sectors); |
194 |
|
q += 4; |
195 |
|
} |
196 |
|
|
197 |
|
*q++ = 1; /* session number */ |
198 |
|
*q++ = 0x14; /* ADR, control */ |
199 |
|
*q++ = 0; /* track number */ |
200 |
|
*q++ = 1; /* point */ |
201 |
|
*q++ = 0; /* min */ |
202 |
|
*q++ = 0; /* sec */ |
203 |
|
*q++ = 0; /* frame */ |
204 |
|
if (msf) { |
205 |
|
*q++ = 0; |
206 |
|
lba_to_msf(q, 0); |
207 |
|
q += 3; |
208 |
|
} else { |
209 |
|
*q++ = 0; |
210 |
|
*q++ = 0; |
211 |
|
*q++ = 0; |
212 |
|
*q++ = 0; |
213 |
|
} |
214 |
|
|
215 |
|
len = q - buf; |
216 |
|
cpu_to_ube16(buf, len - 2); |
217 |
|
return len; |
218 |
|
} |
219 |
|
|
220 |
static void handle_satn(ESPState *s) |
static void handle_satn(ESPState *s) |
221 |
{ |
{ |
222 |
uint8_t buf[32]; |
uint8_t buf[32]; |
270 |
memcpy(&s->ti_buf[8], "QEMU ", 8); |
memcpy(&s->ti_buf[8], "QEMU ", 8); |
271 |
s->ti_buf[2] = 1; |
s->ti_buf[2] = 1; |
272 |
s->ti_buf[3] = 2; |
s->ti_buf[3] = 2; |
273 |
|
s->ti_buf[4] = 32; |
274 |
s->ti_dir = 1; |
s->ti_dir = 1; |
275 |
s->ti_size = 36; |
s->ti_size = 36; |
276 |
break; |
break; |
333 |
s->ti_dir = 0; |
s->ti_dir = 0; |
334 |
break; |
break; |
335 |
} |
} |
336 |
|
case 0x43: |
337 |
|
{ |
338 |
|
int start_track, format, msf, len; |
339 |
|
|
340 |
|
msf = buf[2] & 2; |
341 |
|
format = buf[3] & 0xf; |
342 |
|
start_track = buf[7]; |
343 |
|
bdrv_get_geometry(s->bd[target], &nb_sectors); |
344 |
|
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
345 |
|
switch(format) { |
346 |
|
case 0: |
347 |
|
len = cdrom_read_toc(nb_sectors, buf, msf, start_track); |
348 |
|
if (len < 0) |
349 |
|
goto error_cmd; |
350 |
|
s->ti_size = len; |
351 |
|
break; |
352 |
|
case 1: |
353 |
|
/* multi session : only a single session defined */ |
354 |
|
memset(buf, 0, 12); |
355 |
|
buf[1] = 0x0a; |
356 |
|
buf[2] = 0x01; |
357 |
|
buf[3] = 0x01; |
358 |
|
s->ti_size = 12; |
359 |
|
break; |
360 |
|
case 2: |
361 |
|
len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); |
362 |
|
if (len < 0) |
363 |
|
goto error_cmd; |
364 |
|
s->ti_size = len; |
365 |
|
break; |
366 |
|
default: |
367 |
|
error_cmd: |
368 |
|
DPRINTF("Read TOC error\n"); |
369 |
|
// XXX error handling |
370 |
|
break; |
371 |
|
} |
372 |
|
s->ti_dir = 1; |
373 |
|
break; |
374 |
|
} |
375 |
default: |
default: |
376 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); |
377 |
break; |
break; |