Revision 2e5d83bb
b/Makefile.target | ||
---|---|---|
306 | 306 |
SOUND_HW += fmopl.o adlib.o |
307 | 307 |
endif |
308 | 308 |
|
309 |
# SCSI layer |
|
310 |
VL_OBJS+= scsi-disk.o cdrom.o |
|
311 |
|
|
309 | 312 |
# USB layer |
310 |
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o |
|
313 |
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
|
|
311 | 314 |
|
312 | 315 |
# PCI network cards |
313 | 316 |
VL_OBJS+= ne2000.o rtl8139.o |
b/hw/cdrom.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU ATAPI CD-ROM Emulator |
|
3 |
* |
|
4 |
* Copyright (c) 2006 Fabrice Bellard |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved |
|
26 |
here. */ |
|
27 |
|
|
28 |
#include <vl.h> |
|
29 |
|
|
30 |
static void lba_to_msf(uint8_t *buf, int lba) |
|
31 |
{ |
|
32 |
lba += 150; |
|
33 |
buf[0] = (lba / 75) / 60; |
|
34 |
buf[1] = (lba / 75) % 60; |
|
35 |
buf[2] = lba % 75; |
|
36 |
} |
|
37 |
|
|
38 |
/* same toc as bochs. Return -1 if error or the toc length */ |
|
39 |
/* XXX: check this */ |
|
40 |
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) |
|
41 |
{ |
|
42 |
uint8_t *q; |
|
43 |
int len; |
|
44 |
|
|
45 |
if (start_track > 1 && start_track != 0xaa) |
|
46 |
return -1; |
|
47 |
q = buf + 2; |
|
48 |
*q++ = 1; /* first session */ |
|
49 |
*q++ = 1; /* last session */ |
|
50 |
if (start_track <= 1) { |
|
51 |
*q++ = 0; /* reserved */ |
|
52 |
*q++ = 0x14; /* ADR, control */ |
|
53 |
*q++ = 1; /* track number */ |
|
54 |
*q++ = 0; /* reserved */ |
|
55 |
if (msf) { |
|
56 |
*q++ = 0; /* reserved */ |
|
57 |
lba_to_msf(q, 0); |
|
58 |
q += 3; |
|
59 |
} else { |
|
60 |
/* sector 0 */ |
|
61 |
cpu_to_be32wu((uint32_t *)q, 0); |
|
62 |
q += 4; |
|
63 |
} |
|
64 |
} |
|
65 |
/* lead out track */ |
|
66 |
*q++ = 0; /* reserved */ |
|
67 |
*q++ = 0x16; /* ADR, control */ |
|
68 |
*q++ = 0xaa; /* track number */ |
|
69 |
*q++ = 0; /* reserved */ |
|
70 |
if (msf) { |
|
71 |
*q++ = 0; /* reserved */ |
|
72 |
lba_to_msf(q, nb_sectors); |
|
73 |
q += 3; |
|
74 |
} else { |
|
75 |
cpu_to_be32wu((uint32_t *)q, nb_sectors); |
|
76 |
q += 4; |
|
77 |
} |
|
78 |
len = q - buf; |
|
79 |
cpu_to_be16wu((uint16_t *)buf, len - 2); |
|
80 |
return len; |
|
81 |
} |
|
82 |
|
|
83 |
/* mostly same info as PearPc */ |
|
84 |
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) |
|
85 |
{ |
|
86 |
uint8_t *q; |
|
87 |
int len; |
|
88 |
|
|
89 |
q = buf + 2; |
|
90 |
*q++ = 1; /* first session */ |
|
91 |
*q++ = 1; /* last session */ |
|
92 |
|
|
93 |
*q++ = 1; /* session number */ |
|
94 |
*q++ = 0x14; /* data track */ |
|
95 |
*q++ = 0; /* track number */ |
|
96 |
*q++ = 0xa0; /* lead-in */ |
|
97 |
*q++ = 0; /* min */ |
|
98 |
*q++ = 0; /* sec */ |
|
99 |
*q++ = 0; /* frame */ |
|
100 |
*q++ = 0; |
|
101 |
*q++ = 1; /* first track */ |
|
102 |
*q++ = 0x00; /* disk type */ |
|
103 |
*q++ = 0x00; |
|
104 |
|
|
105 |
*q++ = 1; /* session number */ |
|
106 |
*q++ = 0x14; /* data track */ |
|
107 |
*q++ = 0; /* track number */ |
|
108 |
*q++ = 0xa1; |
|
109 |
*q++ = 0; /* min */ |
|
110 |
*q++ = 0; /* sec */ |
|
111 |
*q++ = 0; /* frame */ |
|
112 |
*q++ = 0; |
|
113 |
*q++ = 1; /* last track */ |
|
114 |
*q++ = 0x00; |
|
115 |
*q++ = 0x00; |
|
116 |
|
|
117 |
*q++ = 1; /* session number */ |
|
118 |
*q++ = 0x14; /* data track */ |
|
119 |
*q++ = 0; /* track number */ |
|
120 |
*q++ = 0xa2; /* lead-out */ |
|
121 |
*q++ = 0; /* min */ |
|
122 |
*q++ = 0; /* sec */ |
|
123 |
*q++ = 0; /* frame */ |
|
124 |
if (msf) { |
|
125 |
*q++ = 0; /* reserved */ |
|
126 |
lba_to_msf(q, nb_sectors); |
|
127 |
q += 3; |
|
128 |
} else { |
|
129 |
cpu_to_be32wu((uint32_t *)q, nb_sectors); |
|
130 |
q += 4; |
|
131 |
} |
|
132 |
|
|
133 |
*q++ = 1; /* session number */ |
|
134 |
*q++ = 0x14; /* ADR, control */ |
|
135 |
*q++ = 0; /* track number */ |
|
136 |
*q++ = 1; /* point */ |
|
137 |
*q++ = 0; /* min */ |
|
138 |
*q++ = 0; /* sec */ |
|
139 |
*q++ = 0; /* frame */ |
|
140 |
if (msf) { |
|
141 |
*q++ = 0; |
|
142 |
lba_to_msf(q, 0); |
|
143 |
q += 3; |
|
144 |
} else { |
|
145 |
*q++ = 0; |
|
146 |
*q++ = 0; |
|
147 |
*q++ = 0; |
|
148 |
*q++ = 0; |
|
149 |
} |
|
150 |
|
|
151 |
len = q - buf; |
|
152 |
cpu_to_be16wu((uint16_t *)buf, len - 2); |
|
153 |
return len; |
|
154 |
} |
|
155 |
|
|
156 |
|
b/hw/esp.c | ||
---|---|---|
38 | 38 |
#define ESPDMA_REGS 4 |
39 | 39 |
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) |
40 | 40 |
#define ESP_MAXREG 0x3f |
41 |
#define TI_BUFSZ 1024*1024 // XXX
|
|
41 |
#define TI_BUFSZ 32
|
|
42 | 42 |
#define DMA_VER 0xa0000000 |
43 | 43 |
#define DMA_INTR 1 |
44 | 44 |
#define DMA_INTREN 0x10 |
45 |
#define DMA_WRITE_MEM 0x100 |
|
45 | 46 |
#define DMA_LOADED 0x04000000 |
46 | 47 |
typedef struct ESPState ESPState; |
47 | 48 |
|
48 |
typedef int ESPDMAFunc(ESPState *s, |
|
49 |
target_phys_addr_t phys_addr, |
|
50 |
int transfer_size1); |
|
51 |
|
|
52 | 49 |
struct ESPState { |
53 | 50 |
BlockDriverState **bd; |
54 | 51 |
uint8_t rregs[ESP_MAXREG]; |
... | ... | |
57 | 54 |
uint32_t espdmaregs[ESPDMA_REGS]; |
58 | 55 |
uint32_t ti_size; |
59 | 56 |
uint32_t ti_rptr, ti_wptr; |
60 |
int ti_dir; |
|
61 | 57 |
uint8_t ti_buf[TI_BUFSZ]; |
62 | 58 |
int dma; |
63 |
ESPDMAFunc *dma_cb; |
|
64 |
int64_t offset, len; |
|
65 |
int target; |
|
59 |
SCSIDevice *scsi_dev[MAX_DISKS]; |
|
60 |
SCSIDevice *current_dev; |
|
66 | 61 |
}; |
67 | 62 |
|
68 | 63 |
#define STAT_DO 0x00 |
... | ... | |
83 | 78 |
#define SEQ_0 0x0 |
84 | 79 |
#define SEQ_CD 0x4 |
85 | 80 |
|
86 |
/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ |
|
87 |
static void lba_to_msf(uint8_t *buf, int lba) |
|
88 |
{ |
|
89 |
lba += 150; |
|
90 |
buf[0] = (lba / 75) / 60; |
|
91 |
buf[1] = (lba / 75) % 60; |
|
92 |
buf[2] = lba % 75; |
|
93 |
} |
|
94 |
|
|
95 |
static inline void cpu_to_ube16(uint8_t *buf, int val) |
|
96 |
{ |
|
97 |
buf[0] = val >> 8; |
|
98 |
buf[1] = val; |
|
99 |
} |
|
100 |
|
|
101 |
static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) |
|
102 |
{ |
|
103 |
buf[0] = val >> 24; |
|
104 |
buf[1] = val >> 16; |
|
105 |
buf[2] = val >> 8; |
|
106 |
buf[3] = val; |
|
107 |
} |
|
108 |
|
|
109 |
/* same toc as bochs. Return -1 if error or the toc length */ |
|
110 |
/* XXX: check this */ |
|
111 |
static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) |
|
112 |
{ |
|
113 |
uint8_t *q; |
|
114 |
int len; |
|
115 |
|
|
116 |
if (start_track > 1 && start_track != 0xaa) |
|
117 |
return -1; |
|
118 |
q = buf + 2; |
|
119 |
*q++ = 1; /* first session */ |
|
120 |
*q++ = 1; /* last session */ |
|
121 |
if (start_track <= 1) { |
|
122 |
*q++ = 0; /* reserved */ |
|
123 |
*q++ = 0x14; /* ADR, control */ |
|
124 |
*q++ = 1; /* track number */ |
|
125 |
*q++ = 0; /* reserved */ |
|
126 |
if (msf) { |
|
127 |
*q++ = 0; /* reserved */ |
|
128 |
lba_to_msf(q, 0); |
|
129 |
q += 3; |
|
130 |
} else { |
|
131 |
/* sector 0 */ |
|
132 |
cpu_to_ube32(q, 0); |
|
133 |
q += 4; |
|
134 |
} |
|
135 |
} |
|
136 |
/* lead out track */ |
|
137 |
*q++ = 0; /* reserved */ |
|
138 |
*q++ = 0x16; /* ADR, control */ |
|
139 |
*q++ = 0xaa; /* track number */ |
|
140 |
*q++ = 0; /* reserved */ |
|
141 |
if (msf) { |
|
142 |
*q++ = 0; /* reserved */ |
|
143 |
lba_to_msf(q, nb_sectors); |
|
144 |
q += 3; |
|
145 |
} else { |
|
146 |
cpu_to_ube32(q, nb_sectors); |
|
147 |
q += 4; |
|
148 |
} |
|
149 |
len = q - buf; |
|
150 |
cpu_to_ube16(buf, len - 2); |
|
151 |
return len; |
|
152 |
} |
|
153 |
|
|
154 |
/* mostly same info as PearPc */ |
|
155 |
static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, |
|
156 |
int session_num) |
|
157 |
{ |
|
158 |
uint8_t *q; |
|
159 |
int len; |
|
160 |
|
|
161 |
q = buf + 2; |
|
162 |
*q++ = 1; /* first session */ |
|
163 |
*q++ = 1; /* last session */ |
|
164 |
|
|
165 |
*q++ = 1; /* session number */ |
|
166 |
*q++ = 0x14; /* data track */ |
|
167 |
*q++ = 0; /* track number */ |
|
168 |
*q++ = 0xa0; /* lead-in */ |
|
169 |
*q++ = 0; /* min */ |
|
170 |
*q++ = 0; /* sec */ |
|
171 |
*q++ = 0; /* frame */ |
|
172 |
*q++ = 0; |
|
173 |
*q++ = 1; /* first track */ |
|
174 |
*q++ = 0x00; /* disk type */ |
|
175 |
*q++ = 0x00; |
|
176 |
|
|
177 |
*q++ = 1; /* session number */ |
|
178 |
*q++ = 0x14; /* data track */ |
|
179 |
*q++ = 0; /* track number */ |
|
180 |
*q++ = 0xa1; |
|
181 |
*q++ = 0; /* min */ |
|
182 |
*q++ = 0; /* sec */ |
|
183 |
*q++ = 0; /* frame */ |
|
184 |
*q++ = 0; |
|
185 |
*q++ = 1; /* last track */ |
|
186 |
*q++ = 0x00; |
|
187 |
*q++ = 0x00; |
|
188 |
|
|
189 |
*q++ = 1; /* session number */ |
|
190 |
*q++ = 0x14; /* data track */ |
|
191 |
*q++ = 0; /* track number */ |
|
192 |
*q++ = 0xa2; /* lead-out */ |
|
193 |
*q++ = 0; /* min */ |
|
194 |
*q++ = 0; /* sec */ |
|
195 |
*q++ = 0; /* frame */ |
|
196 |
if (msf) { |
|
197 |
*q++ = 0; /* reserved */ |
|
198 |
lba_to_msf(q, nb_sectors); |
|
199 |
q += 3; |
|
200 |
} else { |
|
201 |
cpu_to_ube32(q, nb_sectors); |
|
202 |
q += 4; |
|
203 |
} |
|
204 |
|
|
205 |
*q++ = 1; /* session number */ |
|
206 |
*q++ = 0x14; /* ADR, control */ |
|
207 |
*q++ = 0; /* track number */ |
|
208 |
*q++ = 1; /* point */ |
|
209 |
*q++ = 0; /* min */ |
|
210 |
*q++ = 0; /* sec */ |
|
211 |
*q++ = 0; /* frame */ |
|
212 |
if (msf) { |
|
213 |
*q++ = 0; |
|
214 |
lba_to_msf(q, 0); |
|
215 |
q += 3; |
|
216 |
} else { |
|
217 |
*q++ = 0; |
|
218 |
*q++ = 0; |
|
219 |
*q++ = 0; |
|
220 |
*q++ = 0; |
|
221 |
} |
|
222 |
|
|
223 |
len = q - buf; |
|
224 |
cpu_to_ube16(buf, len - 2); |
|
225 |
return len; |
|
226 |
} |
|
227 |
|
|
228 |
static int esp_write_dma_cb(ESPState *s, |
|
229 |
target_phys_addr_t phys_addr, |
|
230 |
int transfer_size1) |
|
231 |
{ |
|
232 |
int len; |
|
233 |
if (bdrv_get_type_hint(s->bd[s->target]) == BDRV_TYPE_CDROM) { |
|
234 |
len = transfer_size1/2048; |
|
235 |
} else { |
|
236 |
len = transfer_size1/512; |
|
237 |
} |
|
238 |
DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", |
|
239 |
s->offset, s->len, s->ti_size, transfer_size1); |
|
240 |
|
|
241 |
bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_rptr, len); |
|
242 |
s->offset+=len; |
|
243 |
return 0; |
|
244 |
} |
|
245 |
|
|
246 | 81 |
static void handle_satn(ESPState *s) |
247 | 82 |
{ |
248 | 83 |
uint8_t buf[32]; |
249 | 84 |
uint32_t dmaptr, dmalen; |
250 |
unsigned int i; |
|
251 |
int64_t nb_sectors; |
|
252 | 85 |
int target; |
86 |
int32_t datalen; |
|
253 | 87 |
|
254 | 88 |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
255 | 89 |
target = s->wregs[4] & 7; |
256 | 90 |
DPRINTF("Select with ATN len %d target %d\n", dmalen, target); |
257 | 91 |
if (s->dma) { |
258 | 92 |
dmaptr = iommu_translate(s->espdmaregs[1]); |
259 |
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); |
|
93 |
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", |
|
94 |
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); |
|
260 | 95 |
cpu_physical_memory_read(dmaptr, buf, dmalen); |
261 | 96 |
} else { |
262 | 97 |
buf[0] = 0; |
263 | 98 |
memcpy(&buf[1], s->ti_buf, dmalen); |
264 | 99 |
dmalen++; |
265 | 100 |
} |
266 |
for (i = 0; i < dmalen; i++) { |
|
267 |
DPRINTF("Command %2.2x\n", buf[i]); |
|
268 |
} |
|
269 |
s->ti_dir = 0; |
|
101 |
|
|
270 | 102 |
s->ti_size = 0; |
271 | 103 |
s->ti_rptr = 0; |
272 | 104 |
s->ti_wptr = 0; |
273 | 105 |
|
274 |
if (target >= 4 || !s->bd[target]) { // No such drive |
|
106 |
if (target >= 4 || !s->scsi_dev[target]) { |
|
107 |
// No such drive |
|
275 | 108 |
s->rregs[4] = STAT_IN; |
276 | 109 |
s->rregs[5] = INTR_DC; |
277 | 110 |
s->rregs[6] = SEQ_0; |
... | ... | |
279 | 112 |
pic_set_irq(s->irq, 1); |
280 | 113 |
return; |
281 | 114 |
} |
282 |
switch (buf[1]) { |
|
283 |
case 0x0: |
|
284 |
DPRINTF("Test Unit Ready (len %d)\n", buf[5]); |
|
285 |
break; |
|
286 |
case 0x12: |
|
287 |
DPRINTF("Inquiry (len %d)\n", buf[5]); |
|
288 |
memset(s->ti_buf, 0, 36); |
|
289 |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { |
|
290 |
s->ti_buf[0] = 5; |
|
291 |
memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); |
|
292 |
} else { |
|
293 |
s->ti_buf[0] = 0; |
|
294 |
memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); |
|
295 |
} |
|
296 |
memcpy(&s->ti_buf[8], "QEMU ", 8); |
|
297 |
s->ti_buf[2] = 1; |
|
298 |
s->ti_buf[3] = 2; |
|
299 |
s->ti_buf[4] = 32; |
|
300 |
s->ti_dir = 1; |
|
301 |
s->ti_size = 36; |
|
302 |
break; |
|
303 |
case 0x1a: |
|
304 |
DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); |
|
305 |
break; |
|
306 |
case 0x25: |
|
307 |
DPRINTF("Read Capacity (len %d)\n", buf[5]); |
|
308 |
memset(s->ti_buf, 0, 8); |
|
309 |
bdrv_get_geometry(s->bd[target], &nb_sectors); |
|
310 |
s->ti_buf[0] = (nb_sectors >> 24) & 0xff; |
|
311 |
s->ti_buf[1] = (nb_sectors >> 16) & 0xff; |
|
312 |
s->ti_buf[2] = (nb_sectors >> 8) & 0xff; |
|
313 |
s->ti_buf[3] = nb_sectors & 0xff; |
|
314 |
s->ti_buf[4] = 0; |
|
315 |
s->ti_buf[5] = 0; |
|
316 |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) |
|
317 |
s->ti_buf[6] = 8; // sector size 2048 |
|
318 |
else |
|
319 |
s->ti_buf[6] = 2; // sector size 512 |
|
320 |
s->ti_buf[7] = 0; |
|
321 |
s->ti_dir = 1; |
|
322 |
s->ti_size = 8; |
|
323 |
break; |
|
324 |
case 0x28: |
|
325 |
{ |
|
326 |
int64_t offset, len; |
|
327 |
|
|
328 |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { |
|
329 |
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; |
|
330 |
len = ((buf[8] << 8) | buf[9]) * 4; |
|
331 |
s->ti_size = len * 2048; |
|
332 |
} else { |
|
333 |
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
|
334 |
len = (buf[8] << 8) | buf[9]; |
|
335 |
s->ti_size = len * 512; |
|
336 |
} |
|
337 |
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); |
|
338 |
if (s->ti_size > TI_BUFSZ) { |
|
339 |
DPRINTF("size too large %d\n", s->ti_size); |
|
340 |
} |
|
341 |
bdrv_read(s->bd[target], offset, s->ti_buf, len); |
|
342 |
// XXX error handling |
|
343 |
s->ti_dir = 1; |
|
344 |
s->ti_rptr = 0; |
|
345 |
break; |
|
346 |
} |
|
347 |
case 0x2a: |
|
348 |
{ |
|
349 |
int64_t offset, len; |
|
350 |
|
|
351 |
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { |
|
352 |
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; |
|
353 |
len = ((buf[8] << 8) | buf[9]) * 4; |
|
354 |
s->ti_size = len * 2048; |
|
355 |
} else { |
|
356 |
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; |
|
357 |
len = (buf[8] << 8) | buf[9]; |
|
358 |
s->ti_size = len * 512; |
|
359 |
} |
|
360 |
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); |
|
361 |
if (s->ti_size > TI_BUFSZ) { |
|
362 |
DPRINTF("size too large %d\n", s->ti_size); |
|
363 |
} |
|
364 |
s->dma_cb = esp_write_dma_cb; |
|
365 |
s->offset = offset; |
|
366 |
s->len = len; |
|
367 |
s->target = target; |
|
368 |
s->ti_rptr = 0; |
|
369 |
// XXX error handling |
|
370 |
s->ti_dir = 0; |
|
371 |
break; |
|
372 |
} |
|
373 |
case 0x43: |
|
374 |
{ |
|
375 |
int start_track, format, msf, len; |
|
376 |
|
|
377 |
msf = buf[2] & 2; |
|
378 |
format = buf[3] & 0xf; |
|
379 |
start_track = buf[7]; |
|
380 |
bdrv_get_geometry(s->bd[target], &nb_sectors); |
|
381 |
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
|
382 |
switch(format) { |
|
383 |
case 0: |
|
384 |
len = cdrom_read_toc(nb_sectors, buf, msf, start_track); |
|
385 |
if (len < 0) |
|
386 |
goto error_cmd; |
|
387 |
s->ti_size = len; |
|
388 |
break; |
|
389 |
case 1: |
|
390 |
/* multi session : only a single session defined */ |
|
391 |
memset(buf, 0, 12); |
|
392 |
buf[1] = 0x0a; |
|
393 |
buf[2] = 0x01; |
|
394 |
buf[3] = 0x01; |
|
395 |
s->ti_size = 12; |
|
396 |
break; |
|
397 |
case 2: |
|
398 |
len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); |
|
399 |
if (len < 0) |
|
400 |
goto error_cmd; |
|
401 |
s->ti_size = len; |
|
402 |
break; |
|
403 |
default: |
|
404 |
error_cmd: |
|
405 |
DPRINTF("Read TOC error\n"); |
|
406 |
// XXX error handling |
|
407 |
break; |
|
408 |
} |
|
409 |
s->ti_dir = 1; |
|
410 |
break; |
|
115 |
s->current_dev = s->scsi_dev[target]; |
|
116 |
datalen = scsi_send_command(s->current_dev, 0, &buf[1]); |
|
117 |
if (datalen == 0) { |
|
118 |
s->ti_size = 0; |
|
119 |
} else { |
|
120 |
s->rregs[4] = STAT_IN | STAT_TC; |
|
121 |
if (datalen > 0) { |
|
122 |
s->rregs[4] |= STAT_DI; |
|
123 |
s->ti_size = datalen; |
|
124 |
} else { |
|
125 |
s->rregs[4] |= STAT_DO; |
|
126 |
s->ti_size = -datalen; |
|
411 | 127 |
} |
412 |
default: |
|
413 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); |
|
414 |
break; |
|
415 | 128 |
} |
416 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; |
|
417 | 129 |
s->rregs[5] = INTR_BS | INTR_FC; |
418 | 130 |
s->rregs[6] = SEQ_CD; |
419 | 131 |
s->espdmaregs[0] |= DMA_INTR; |
... | ... | |
427 | 139 |
DPRINTF("Transfer status len %d\n", len); |
428 | 140 |
if (s->dma) { |
429 | 141 |
dmaptr = iommu_translate(s->espdmaregs[1]); |
430 |
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); |
|
142 |
DPRINTF("DMA Direction: %c\n", |
|
143 |
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); |
|
431 | 144 |
cpu_physical_memory_write(dmaptr, buf, len); |
432 | 145 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
433 | 146 |
s->rregs[5] = INTR_BS | INTR_FC; |
... | ... | |
446 | 159 |
|
447 | 160 |
static const uint8_t okbuf[] = {0, 0}; |
448 | 161 |
|
162 |
static void esp_command_complete(void *opaque, uint32_t tag, int fail) |
|
163 |
{ |
|
164 |
ESPState *s = (ESPState *)opaque; |
|
165 |
|
|
166 |
DPRINTF("SCSI Command complete\n"); |
|
167 |
if (s->ti_size != 0) |
|
168 |
DPRINTF("SCSI command completed unexpectedly\n"); |
|
169 |
s->ti_size = 0; |
|
170 |
/* ??? Report failures. */ |
|
171 |
if (fail) |
|
172 |
DPRINTF("Command failed\n"); |
|
173 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
|
174 |
} |
|
175 |
|
|
449 | 176 |
static void handle_ti(ESPState *s) |
450 | 177 |
{ |
451 | 178 |
uint32_t dmaptr, dmalen, minlen, len, from, to; |
452 | 179 |
unsigned int i; |
180 |
int to_device; |
|
181 |
uint8_t buf[TARGET_PAGE_SIZE]; |
|
453 | 182 |
|
454 | 183 |
dmalen = s->wregs[0] | (s->wregs[1] << 8); |
455 | 184 |
if (dmalen==0) { |
... | ... | |
460 | 189 |
DPRINTF("Transfer Information len %d\n", minlen); |
461 | 190 |
if (s->dma) { |
462 | 191 |
dmaptr = iommu_translate(s->espdmaregs[1]); |
463 |
DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_rptr, s->ti_dir); |
|
192 |
/* Check if the transfer writes to to reads from the device. */ |
|
193 |
to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; |
|
194 |
DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", |
|
195 |
to_device ? 'r': 'w', dmaptr, s->ti_size); |
|
464 | 196 |
from = s->espdmaregs[1]; |
465 | 197 |
to = from + minlen; |
466 | 198 |
for (i = 0; i < minlen; i += len, from += len) { |
... | ... | |
471 | 203 |
len = to - from; |
472 | 204 |
} |
473 | 205 |
DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); |
474 |
if (s->ti_dir) |
|
475 |
cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_rptr + i], len); |
|
476 |
else |
|
477 |
cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_rptr + i], len); |
|
206 |
s->ti_size -= len; |
|
207 |
if (to_device) { |
|
208 |
cpu_physical_memory_read(dmaptr, buf, len); |
|
209 |
scsi_write_data(s->current_dev, buf, len); |
|
210 |
} else { |
|
211 |
scsi_read_data(s->current_dev, buf, len); |
|
212 |
cpu_physical_memory_write(dmaptr, buf, len); |
|
213 |
} |
|
478 | 214 |
} |
479 |
if (s->dma_cb) { |
|
480 |
s->dma_cb(s, s->espdmaregs[1], minlen); |
|
481 |
} |
|
482 |
if (minlen < s->ti_size) { |
|
483 |
s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir ? STAT_DO : STAT_DI); |
|
215 |
if (s->ti_size) { |
|
216 |
s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); |
|
484 | 217 |
s->ti_size -= minlen; |
485 |
s->ti_rptr += minlen; |
|
486 |
} else { |
|
487 |
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; |
|
488 |
s->dma_cb = NULL; |
|
489 |
s->offset = 0; |
|
490 |
s->len = 0; |
|
491 |
s->target = 0; |
|
492 |
s->ti_rptr = 0; |
|
493 | 218 |
} |
494 | 219 |
s->rregs[5] = INTR_BS; |
495 | 220 |
s->rregs[6] = 0; |
496 | 221 |
s->rregs[7] = 0; |
497 | 222 |
s->espdmaregs[0] |= DMA_INTR; |
498 |
} else { |
|
499 |
s->ti_size = minlen; |
|
500 |
s->ti_rptr = 0; |
|
501 |
s->ti_wptr = 0; |
|
502 |
s->rregs[7] = minlen; |
|
503 | 223 |
} |
504 | 224 |
pic_set_irq(s->irq, 1); |
505 | 225 |
} |
... | ... | |
514 | 234 |
s->ti_size = 0; |
515 | 235 |
s->ti_rptr = 0; |
516 | 236 |
s->ti_wptr = 0; |
517 |
s->ti_dir = 0; |
|
518 | 237 |
s->dma = 0; |
519 |
s->dma_cb = NULL; |
|
520 | 238 |
} |
521 | 239 |
|
522 | 240 |
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) |
... | ... | |
531 | 249 |
// FIFO |
532 | 250 |
if (s->ti_size > 0) { |
533 | 251 |
s->ti_size--; |
534 |
s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; |
|
252 |
if ((s->rregs[4] & 6) == 0) { |
|
253 |
/* Data in/out. */ |
|
254 |
scsi_read_data(s->current_dev, &s->rregs[2], 0); |
|
255 |
} else { |
|
256 |
s->rregs[2] = s->ti_buf[s->ti_rptr++]; |
|
257 |
} |
|
535 | 258 |
pic_set_irq(s->irq, 1); |
536 | 259 |
} |
537 | 260 |
if (s->ti_size == 0) { |
... | ... | |
566 | 289 |
break; |
567 | 290 |
case 2: |
568 | 291 |
// FIFO |
569 |
s->ti_size++; |
|
570 |
s->ti_buf[s->ti_wptr++] = val & 0xff; |
|
292 |
if ((s->rregs[4] & 6) == 0) { |
|
293 |
uint8_t buf; |
|
294 |
buf = val & 0xff; |
|
295 |
s->ti_size--; |
|
296 |
scsi_write_data(s->current_dev, &buf, 0); |
|
297 |
} else { |
|
298 |
s->ti_size++; |
|
299 |
s->ti_buf[s->ti_wptr++] = val & 0xff; |
|
300 |
} |
|
571 | 301 |
break; |
572 | 302 |
case 3: |
573 | 303 |
s->rregs[saddr] = val; |
... | ... | |
723 | 453 |
qemu_put_be32s(f, &s->ti_size); |
724 | 454 |
qemu_put_be32s(f, &s->ti_rptr); |
725 | 455 |
qemu_put_be32s(f, &s->ti_wptr); |
726 |
qemu_put_be32s(f, &s->ti_dir); |
|
727 | 456 |
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); |
728 | 457 |
qemu_put_be32s(f, &s->dma); |
729 | 458 |
} |
... | ... | |
744 | 473 |
qemu_get_be32s(f, &s->ti_size); |
745 | 474 |
qemu_get_be32s(f, &s->ti_rptr); |
746 | 475 |
qemu_get_be32s(f, &s->ti_wptr); |
747 |
qemu_get_be32s(f, &s->ti_dir); |
|
748 | 476 |
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); |
749 | 477 |
qemu_get_be32s(f, &s->dma); |
750 | 478 |
|
... | ... | |
755 | 483 |
{ |
756 | 484 |
ESPState *s; |
757 | 485 |
int esp_io_memory, espdma_io_memory; |
486 |
int i; |
|
758 | 487 |
|
759 | 488 |
s = qemu_mallocz(sizeof(ESPState)); |
760 | 489 |
if (!s) |
... | ... | |
773 | 502 |
|
774 | 503 |
register_savevm("esp", espaddr, 1, esp_save, esp_load, s); |
775 | 504 |
qemu_register_reset(esp_reset, s); |
505 |
for (i = 0; i < MAX_DISKS; i++) { |
|
506 |
if (bs_table[i]) { |
|
507 |
s->scsi_dev[i] = |
|
508 |
scsi_disk_init(bs_table[i], esp_command_complete, s); |
|
509 |
} |
|
510 |
} |
|
776 | 511 |
} |
777 | 512 |
|
b/hw/ide.c | ||
---|---|---|
1082 | 1082 |
} |
1083 | 1083 |
} |
1084 | 1084 |
|
1085 |
/* same toc as bochs. Return -1 if error or the toc length */ |
|
1086 |
/* XXX: check this */ |
|
1087 |
static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) |
|
1088 |
{ |
|
1089 |
uint8_t *q; |
|
1090 |
int nb_sectors, len; |
|
1091 |
|
|
1092 |
if (start_track > 1 && start_track != 0xaa) |
|
1093 |
return -1; |
|
1094 |
q = buf + 2; |
|
1095 |
*q++ = 1; /* first session */ |
|
1096 |
*q++ = 1; /* last session */ |
|
1097 |
if (start_track <= 1) { |
|
1098 |
*q++ = 0; /* reserved */ |
|
1099 |
*q++ = 0x14; /* ADR, control */ |
|
1100 |
*q++ = 1; /* track number */ |
|
1101 |
*q++ = 0; /* reserved */ |
|
1102 |
if (msf) { |
|
1103 |
*q++ = 0; /* reserved */ |
|
1104 |
lba_to_msf(q, 0); |
|
1105 |
q += 3; |
|
1106 |
} else { |
|
1107 |
/* sector 0 */ |
|
1108 |
cpu_to_ube32(q, 0); |
|
1109 |
q += 4; |
|
1110 |
} |
|
1111 |
} |
|
1112 |
/* lead out track */ |
|
1113 |
*q++ = 0; /* reserved */ |
|
1114 |
*q++ = 0x16; /* ADR, control */ |
|
1115 |
*q++ = 0xaa; /* track number */ |
|
1116 |
*q++ = 0; /* reserved */ |
|
1117 |
nb_sectors = s->nb_sectors >> 2; |
|
1118 |
if (msf) { |
|
1119 |
*q++ = 0; /* reserved */ |
|
1120 |
lba_to_msf(q, nb_sectors); |
|
1121 |
q += 3; |
|
1122 |
} else { |
|
1123 |
cpu_to_ube32(q, nb_sectors); |
|
1124 |
q += 4; |
|
1125 |
} |
|
1126 |
len = q - buf; |
|
1127 |
cpu_to_ube16(buf, len - 2); |
|
1128 |
return len; |
|
1129 |
} |
|
1130 |
|
|
1131 |
/* mostly same info as PearPc */ |
|
1132 |
static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, |
|
1133 |
int session_num) |
|
1134 |
{ |
|
1135 |
uint8_t *q; |
|
1136 |
int nb_sectors, len; |
|
1137 |
|
|
1138 |
q = buf + 2; |
|
1139 |
*q++ = 1; /* first session */ |
|
1140 |
*q++ = 1; /* last session */ |
|
1141 |
|
|
1142 |
*q++ = 1; /* session number */ |
|
1143 |
*q++ = 0x14; /* data track */ |
|
1144 |
*q++ = 0; /* track number */ |
|
1145 |
*q++ = 0xa0; /* lead-in */ |
|
1146 |
*q++ = 0; /* min */ |
|
1147 |
*q++ = 0; /* sec */ |
|
1148 |
*q++ = 0; /* frame */ |
|
1149 |
*q++ = 0; |
|
1150 |
*q++ = 1; /* first track */ |
|
1151 |
*q++ = 0x00; /* disk type */ |
|
1152 |
*q++ = 0x00; |
|
1153 |
|
|
1154 |
*q++ = 1; /* session number */ |
|
1155 |
*q++ = 0x14; /* data track */ |
|
1156 |
*q++ = 0; /* track number */ |
|
1157 |
*q++ = 0xa1; |
|
1158 |
*q++ = 0; /* min */ |
|
1159 |
*q++ = 0; /* sec */ |
|
1160 |
*q++ = 0; /* frame */ |
|
1161 |
*q++ = 0; |
|
1162 |
*q++ = 1; /* last track */ |
|
1163 |
*q++ = 0x00; |
|
1164 |
*q++ = 0x00; |
|
1165 |
|
|
1166 |
*q++ = 1; /* session number */ |
|
1167 |
*q++ = 0x14; /* data track */ |
|
1168 |
*q++ = 0; /* track number */ |
|
1169 |
*q++ = 0xa2; /* lead-out */ |
|
1170 |
*q++ = 0; /* min */ |
|
1171 |
*q++ = 0; /* sec */ |
|
1172 |
*q++ = 0; /* frame */ |
|
1173 |
nb_sectors = s->nb_sectors >> 2; |
|
1174 |
if (msf) { |
|
1175 |
*q++ = 0; /* reserved */ |
|
1176 |
lba_to_msf(q, nb_sectors); |
|
1177 |
q += 3; |
|
1178 |
} else { |
|
1179 |
cpu_to_ube32(q, nb_sectors); |
|
1180 |
q += 4; |
|
1181 |
} |
|
1182 |
|
|
1183 |
*q++ = 1; /* session number */ |
|
1184 |
*q++ = 0x14; /* ADR, control */ |
|
1185 |
*q++ = 0; /* track number */ |
|
1186 |
*q++ = 1; /* point */ |
|
1187 |
*q++ = 0; /* min */ |
|
1188 |
*q++ = 0; /* sec */ |
|
1189 |
*q++ = 0; /* frame */ |
|
1190 |
if (msf) { |
|
1191 |
*q++ = 0; |
|
1192 |
lba_to_msf(q, 0); |
|
1193 |
q += 3; |
|
1194 |
} else { |
|
1195 |
*q++ = 0; |
|
1196 |
*q++ = 0; |
|
1197 |
*q++ = 0; |
|
1198 |
*q++ = 0; |
|
1199 |
} |
|
1200 |
|
|
1201 |
len = q - buf; |
|
1202 |
cpu_to_ube16(buf, len - 2); |
|
1203 |
return len; |
|
1204 |
} |
|
1205 |
|
|
1206 | 1085 |
static void ide_atapi_cmd(IDEState *s) |
1207 | 1086 |
{ |
1208 | 1087 |
const uint8_t *packet; |
... | ... | |
1449 | 1328 |
start_track = packet[6]; |
1450 | 1329 |
switch(format) { |
1451 | 1330 |
case 0: |
1452 |
len = cdrom_read_toc(s, buf, msf, start_track); |
|
1331 |
len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track);
|
|
1453 | 1332 |
if (len < 0) |
1454 | 1333 |
goto error_cmd; |
1455 | 1334 |
ide_atapi_cmd_reply(s, len, max_len); |
... | ... | |
1463 | 1342 |
ide_atapi_cmd_reply(s, 12, max_len); |
1464 | 1343 |
break; |
1465 | 1344 |
case 2: |
1466 |
len = cdrom_read_toc_raw(s, buf, msf, start_track); |
|
1345 |
len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track);
|
|
1467 | 1346 |
if (len < 0) |
1468 | 1347 |
goto error_cmd; |
1469 | 1348 |
ide_atapi_cmd_reply(s, len, max_len); |
b/hw/scsi-disk.c | ||
---|---|---|
1 |
/* |
|
2 |
* SCSI Device emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2006 CodeSourcery. |
|
5 |
* Based on code by Fabrice Bellard |
|
6 |
* |
|
7 |
* Written by Paul Brook |
|
8 |
* |
|
9 |
* This code is licenced under the LGPL. |
|
10 |
*/ |
|
11 |
|
|
12 |
//#define DEBUG_SCSI |
|
13 |
|
|
14 |
#ifdef DEBUG_SCSI |
|
15 |
#define DPRINTF(fmt, args...) \ |
|
16 |
do { printf("scsi-disk: " fmt , ##args); } while (0) |
|
17 |
#else |
|
18 |
#define DPRINTF(fmt, args...) do {} while(0) |
|
19 |
#endif |
|
20 |
|
|
21 |
#define BADF(fmt, args...) \ |
|
22 |
do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) |
|
23 |
|
|
24 |
#include "vl.h" |
|
25 |
|
|
26 |
#define SENSE_NO_SENSE 0 |
|
27 |
#define SENSE_ILLEGAL_REQUEST 5 |
|
28 |
|
|
29 |
struct SCSIDevice |
|
30 |
{ |
|
31 |
int command; |
|
32 |
uint32_t tag; |
|
33 |
BlockDriverState *bdrv; |
|
34 |
int sector_size; |
|
35 |
/* When transfering data buf_pos and buf_len contain a partially |
|
36 |
transferred block of data (or response to a command), and |
|
37 |
sector/sector_count identify any remaining sectors. */ |
|
38 |
/* ??? We should probably keep track of whether the data trasfer is |
|
39 |
a read or a write. Currently we rely on the host getting it right. */ |
|
40 |
int sector; |
|
41 |
int sector_count; |
|
42 |
int buf_pos; |
|
43 |
int buf_len; |
|
44 |
int sense; |
|
45 |
char buf[2048]; |
|
46 |
scsi_completionfn completion; |
|
47 |
void *opaque; |
|
48 |
}; |
|
49 |
|
|
50 |
static void scsi_command_complete(SCSIDevice *s, int sense) |
|
51 |
{ |
|
52 |
s->sense = sense; |
|
53 |
s->completion(s->opaque, s->tag, sense != SENSE_NO_SENSE); |
|
54 |
} |
|
55 |
|
|
56 |
/* Read data from a scsi device. Returns nonzero on failure. */ |
|
57 |
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) |
|
58 |
{ |
|
59 |
uint32_t n; |
|
60 |
|
|
61 |
DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count); |
|
62 |
if (s->buf_len == 0 && s->sector_count == 0) |
|
63 |
return 1; |
|
64 |
|
|
65 |
if (s->buf_len) { |
|
66 |
n = s->buf_len; |
|
67 |
if (n > len) |
|
68 |
n = len; |
|
69 |
memcpy(data, s->buf + s->buf_pos, n); |
|
70 |
s->buf_pos += n; |
|
71 |
s->buf_len -= n; |
|
72 |
data += n; |
|
73 |
len -= n; |
|
74 |
if (s->buf_len == 0) |
|
75 |
s->buf_pos = 0; |
|
76 |
} |
|
77 |
|
|
78 |
n = len / s->sector_size; |
|
79 |
if (n > s->sector_count) |
|
80 |
n = s->sector_count; |
|
81 |
|
|
82 |
if (n != 0) { |
|
83 |
bdrv_read(s->bdrv, s->sector, data, n); |
|
84 |
data += n * s->sector_size; |
|
85 |
len -= n * s->sector_size; |
|
86 |
s->sector += n; |
|
87 |
s->sector_count -= n; |
|
88 |
} |
|
89 |
|
|
90 |
if (len && s->sector_count) { |
|
91 |
bdrv_read(s->bdrv, s->sector, s->buf, 1); |
|
92 |
s->sector++; |
|
93 |
s->sector_count--; |
|
94 |
s->buf_pos = 0; |
|
95 |
s->buf_len = s->sector_size; |
|
96 |
/* Recurse to complete the partial read. */ |
|
97 |
return scsi_read_data(s, data, len); |
|
98 |
} |
|
99 |
|
|
100 |
if (len != 0) |
|
101 |
return 1; |
|
102 |
|
|
103 |
if (s->buf_len == 0 && s->sector_count == 0) |
|
104 |
scsi_command_complete(s, SENSE_NO_SENSE); |
|
105 |
|
|
106 |
return 0; |
|
107 |
} |
|
108 |
|
|
109 |
/* Read data to a scsi device. Returns nonzero on failure. */ |
|
110 |
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) |
|
111 |
{ |
|
112 |
uint32_t n; |
|
113 |
|
|
114 |
DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count); |
|
115 |
if (s->buf_pos != 0) { |
|
116 |
BADF("Bad state on write\n"); |
|
117 |
return 1; |
|
118 |
} |
|
119 |
|
|
120 |
if (s->sector_count == 0) |
|
121 |
return 1; |
|
122 |
|
|
123 |
if (s->buf_len != 0 || len < s->sector_size) { |
|
124 |
n = s->sector_size - s->buf_len; |
|
125 |
if (n > len) |
|
126 |
n = len; |
|
127 |
|
|
128 |
memcpy(s->buf + s->buf_len, data, n); |
|
129 |
data += n; |
|
130 |
s->buf_len += n; |
|
131 |
len -= n; |
|
132 |
if (s->buf_len == s->sector_size) { |
|
133 |
/* A full sector has been accumulated. Write it to disk. */ |
|
134 |
bdrv_write(s->bdrv, s->sector, s->buf, 1); |
|
135 |
s->buf_len = 0; |
|
136 |
s->sector++; |
|
137 |
s->sector_count--; |
|
138 |
} |
|
139 |
} |
|
140 |
|
|
141 |
n = len / s->sector_size; |
|
142 |
if (n > s->sector_count) |
|
143 |
n = s->sector_count; |
|
144 |
|
|
145 |
if (n != 0) { |
|
146 |
bdrv_write(s->bdrv, s->sector, data, n); |
|
147 |
data += n * s->sector_size; |
|
148 |
len -= n * s->sector_size; |
|
149 |
s->sector += n; |
|
150 |
s->sector_count -= n; |
|
151 |
} |
|
152 |
|
|
153 |
if (len >= s->sector_size) |
|
154 |
return 1; |
|
155 |
|
|
156 |
if (len && s->sector_count) { |
|
157 |
/* Recurse to complete the partial write. */ |
|
158 |
return scsi_write_data(s, data, len); |
|
159 |
} |
|
160 |
|
|
161 |
if (len != 0) |
|
162 |
return 1; |
|
163 |
|
|
164 |
if (s->sector_count == 0) |
|
165 |
scsi_command_complete(s, SENSE_NO_SENSE); |
|
166 |
|
|
167 |
return 0; |
|
168 |
} |
|
169 |
|
|
170 |
/* Execute a scsi command. Returns the length of the data expected by the |
|
171 |
command. This will be Positive for data transfers from the device |
|
172 |
(eg. disk reads), negative for transfers to the device (eg. disk writes), |
|
173 |
and zero if the command does not transfer any data. */ |
|
174 |
|
|
175 |
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) |
|
176 |
{ |
|
177 |
int64_t nb_sectors; |
|
178 |
uint32_t lba; |
|
179 |
uint32_t len; |
|
180 |
int cmdlen; |
|
181 |
int is_write; |
|
182 |
|
|
183 |
s->command = buf[0]; |
|
184 |
s->tag = tag; |
|
185 |
s->sector_count = 0; |
|
186 |
s->buf_pos = 0; |
|
187 |
s->buf_len = 0; |
|
188 |
is_write = 0; |
|
189 |
DPRINTF("Command: 0x%02x", buf[0]); |
|
190 |
switch (s->command >> 5) { |
|
191 |
case 0: |
|
192 |
lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); |
|
193 |
len = buf[4]; |
|
194 |
cmdlen = 6; |
|
195 |
break; |
|
196 |
case 1: |
|
197 |
case 2: |
|
198 |
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
199 |
len = buf[8] | (buf[7] << 8); |
|
200 |
cmdlen = 10; |
|
201 |
break; |
|
202 |
case 4: |
|
203 |
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
204 |
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); |
|
205 |
cmdlen = 16; |
|
206 |
break; |
|
207 |
case 5: |
|
208 |
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); |
|
209 |
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); |
|
210 |
cmdlen = 12; |
|
211 |
break; |
|
212 |
default: |
|
213 |
BADF("Unsupported command length\n"); |
|
214 |
goto fail; |
|
215 |
} |
|
216 |
#ifdef DEBUG_SCSI |
|
217 |
{ |
|
218 |
int i; |
|
219 |
for (i = 1; i < cmdlen; i++) { |
|
220 |
printf(" 0x%02x", buf[i]); |
|
221 |
} |
|
222 |
printf("\n"); |
|
223 |
} |
|
224 |
#endif |
|
225 |
if (buf[1] >> 5) { |
|
226 |
/* Only LUN 0 supported. */ |
|
227 |
goto fail; |
|
228 |
} |
|
229 |
switch (s->command) { |
|
230 |
case 0x0: |
|
231 |
DPRINTF("Test Unit Ready\n"); |
|
232 |
break; |
|
233 |
case 0x03: |
|
234 |
DPRINTF("Request Sense (len %d)\n", len); |
|
235 |
if (len < 4) |
|
236 |
goto fail; |
|
237 |
memset(buf, 0, 4); |
|
238 |
s->buf[0] = 0xf0; |
|
239 |
s->buf[1] = 0; |
|
240 |
s->buf[2] = s->sense; |
|
241 |
s->buf_len = 4; |
|
242 |
break; |
|
243 |
case 0x12: |
|
244 |
DPRINTF("Inquiry (len %d)\n", len); |
|
245 |
if (len < 36) { |
|
246 |
BADF("Inquiry buffer too small (%d)\n", len); |
|
247 |
} |
|
248 |
memset(s->buf, 0, 36); |
|
249 |
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
250 |
s->buf[0] = 5; |
|
251 |
s->buf[1] = 0x80; |
|
252 |
memcpy(&s->buf[16], "QEMU CDROM ", 16); |
|
253 |
} else { |
|
254 |
s->buf[0] = 0; |
|
255 |
memcpy(&s->buf[16], "QEMU HARDDISK ", 16); |
|
256 |
} |
|
257 |
memcpy(&s->buf[8], "QEMU ", 8); |
|
258 |
s->buf[2] = 3; /* SCSI-3 */ |
|
259 |
s->buf[3] = 2; /* Format 2 */ |
|
260 |
s->buf[4] = 32; |
|
261 |
s->buf_len = 36; |
|
262 |
break; |
|
263 |
case 0x16: |
|
264 |
DPRINTF("Reserve(6)\n"); |
|
265 |
if (buf[1] & 1) |
|
266 |
goto fail; |
|
267 |
break; |
|
268 |
case 0x17: |
|
269 |
DPRINTF("Release(6)\n"); |
|
270 |
if (buf[1] & 1) |
|
271 |
goto fail; |
|
272 |
break; |
|
273 |
case 0x1a: |
|
274 |
DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[2], len); |
|
275 |
memset(s->buf, 0, 4); |
|
276 |
s->buf[0] = 0x16; /* Mode data length (4 + 0x12). */ |
|
277 |
s->buf[1] = 0; /* Default media type. */ |
|
278 |
s->buf[2] = 0; /* Write enabled. */ |
|
279 |
s->buf[3] = 0; /* Block descriptor length. */ |
|
280 |
/* Caching page. */ |
|
281 |
s->buf[4 + 0] = 8; |
|
282 |
s->buf[4 + 1] = 0x12; |
|
283 |
s->buf[4 + 2] = 4; /* WCE */ |
|
284 |
if (len > 0x16) |
|
285 |
len = 0x16; |
|
286 |
s->buf_len = len; |
|
287 |
break; |
|
288 |
case 0x25: |
|
289 |
DPRINTF("Read Capacity\n"); |
|
290 |
/* The normal LEN field for this command is zero. */ |
|
291 |
memset(s->buf, 0, 8); |
|
292 |
bdrv_get_geometry(s->bdrv, &nb_sectors); |
|
293 |
s->buf[0] = (nb_sectors >> 24) & 0xff; |
|
294 |
s->buf[1] = (nb_sectors >> 16) & 0xff; |
|
295 |
s->buf[2] = (nb_sectors >> 8) & 0xff; |
|
296 |
s->buf[3] = nb_sectors & 0xff; |
|
297 |
s->buf[4] = 0; |
|
298 |
s->buf[5] = 0; |
|
299 |
s->buf[6] = s->sector_size >> 8; |
|
300 |
s->buf[7] = s->sector_size & 0xff; |
|
301 |
s->buf_len = 8; |
|
302 |
break; |
|
303 |
case 0x08: |
|
304 |
case 0x28: |
|
305 |
DPRINTF("Read (sector %d, count %d)\n", lba, len); |
|
306 |
s->sector = lba; |
|
307 |
s->sector_count = len; |
|
308 |
break; |
|
309 |
case 0x0a: |
|
310 |
case 0x2a: |
|
311 |
DPRINTF("Write (sector %d, count %d)\n", lba, len); |
|
312 |
s->sector = lba; |
|
313 |
s->sector_count = len; |
|
314 |
is_write = 1; |
|
315 |
break; |
|
316 |
case 0x43: |
|
317 |
{ |
|
318 |
int start_track, format, msf; |
|
319 |
|
|
320 |
msf = buf[1] & 2; |
|
321 |
format = buf[2] & 0xf; |
|
322 |
start_track = buf[6]; |
|
323 |
bdrv_get_geometry(s->bdrv, &nb_sectors); |
|
324 |
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); |
|
325 |
switch(format) { |
|
326 |
case 0: |
|
327 |
len = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); |
|
328 |
if (len < 0) |
|
329 |
goto error_cmd; |
|
330 |
s->buf_len = len; |
|
331 |
break; |
|
332 |
case 1: |
|
333 |
/* multi session : only a single session defined */ |
|
334 |
memset(s->buf, 0, 12); |
|
335 |
s->buf[1] = 0x0a; |
|
336 |
s->buf[2] = 0x01; |
|
337 |
s->buf[3] = 0x01; |
|
338 |
s->buf_len = 12; |
|
339 |
break; |
|
340 |
case 2: |
|
341 |
len = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); |
|
342 |
if (len < 0) |
|
343 |
goto error_cmd; |
|
344 |
s->buf_len = len; |
|
345 |
break; |
|
346 |
default: |
|
347 |
error_cmd: |
|
348 |
DPRINTF("Read TOC error\n"); |
|
349 |
goto fail; |
|
350 |
} |
|
351 |
break; |
|
352 |
} |
|
353 |
case 0x56: |
|
354 |
DPRINTF("Reserve(10)\n"); |
|
355 |
if (buf[1] & 3) |
|
356 |
goto fail; |
|
357 |
break; |
|
358 |
case 0x57: |
|
359 |
DPRINTF("Release(10)\n"); |
|
360 |
if (buf[1] & 3) |
|
361 |
goto fail; |
|
362 |
break; |
|
363 |
case 0xa0: |
|
364 |
DPRINTF("Report LUNs (len %d)\n", len); |
|
365 |
if (len < 16) |
|
366 |
goto fail; |
|
367 |
memset(s->buf, 0, 16); |
|
368 |
s->buf[3] = 8; |
|
369 |
s->buf_len = 16; |
|
370 |
break; |
|
371 |
default: |
|
372 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
|
373 |
fail: |
|
374 |
scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); |
|
375 |
return 0; |
|
376 |
} |
|
377 |
if (s->sector_count == 0 && s->buf_len == 0) { |
|
378 |
scsi_command_complete(s, SENSE_NO_SENSE); |
|
379 |
} |
|
380 |
len = s->sector_count * s->sector_size + s->buf_len; |
|
381 |
return is_write ? -len : len; |
|
382 |
} |
|
383 |
|
|
384 |
void scsi_disk_destroy(SCSIDevice *s) |
|
385 |
{ |
|
386 |
bdrv_close(s->bdrv); |
|
387 |
qemu_free(s); |
|
388 |
} |
|
389 |
|
|
390 |
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, |
|
391 |
scsi_completionfn completion, |
|
392 |
void *opaque) |
|
393 |
{ |
|
394 |
SCSIDevice *s; |
|
395 |
|
|
396 |
s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); |
|
397 |
s->bdrv = bdrv; |
|
398 |
s->completion = completion; |
|
399 |
s->opaque = opaque; |
|
400 |
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { |
|
401 |
s->sector_size = 2048; |
|
402 |
} else { |
|
403 |
s->sector_size = 512; |
|
404 |
} |
|
405 |
|
|
406 |
return s; |
|
407 |
} |
|
408 |
|
b/hw/usb-hid.c | ||
---|---|---|
323 | 323 |
return l; |
324 | 324 |
} |
325 | 325 |
|
326 |
static void usb_mouse_handle_reset(USBDevice *dev) |
|
326 |
static void usb_mouse_handle_reset(USBDevice *dev, int destroy)
|
|
327 | 327 |
{ |
328 | 328 |
USBMouseState *s = (USBMouseState *)dev; |
329 | 329 |
|
330 |
if (destroy) { |
|
331 |
qemu_add_mouse_event_handler(NULL, NULL, 0); |
|
332 |
qemu_free(s); |
|
333 |
return; |
|
334 |
} |
|
335 |
|
|
330 | 336 |
s->dx = 0; |
331 | 337 |
s->dy = 0; |
332 | 338 |
s->dz = 0; |
b/hw/usb-hub.c | ||
---|---|---|
199 | 199 |
} |
200 | 200 |
} |
201 | 201 |
|
202 |
static void usb_hub_handle_reset(USBDevice *dev) |
|
202 |
static void usb_hub_handle_reset(USBDevice *dev, int destroy)
|
|
203 | 203 |
{ |
204 | 204 |
/* XXX: do it */ |
205 |
if (destroy) |
|
206 |
qemu_free(dev); |
|
205 | 207 |
} |
206 | 208 |
|
207 | 209 |
static int usb_hub_handle_control(USBDevice *dev, int request, int value, |
b/hw/usb-msd.c | ||
---|---|---|
1 |
/* |
|
2 |
* USB Mass Storage Device emulation |
|
3 |
* |
|
4 |
* Copyright (c) 2006 CodeSourcery. |
|
5 |
* Written by Paul Brook |
|
6 |
* |
|
7 |
* This code is licenced under the LGPL. |
|
8 |
*/ |
|
9 |
|
|
10 |
#include "vl.h" |
|
11 |
|
|
12 |
//#define DEBUG_MSD |
|
13 |
|
|
14 |
#ifdef DEBUG_MSD |
|
15 |
#define DPRINTF(fmt, args...) \ |
|
16 |
do { printf("usb-msd: " fmt , ##args); } while (0) |
|
17 |
#else |
|
18 |
#define DPRINTF(fmt, args...) do {} while(0) |
|
19 |
#endif |
|
20 |
|
|
21 |
/* USB requests. */ |
|
22 |
#define MassStorageReset 0xff |
|
23 |
#define GetMaxLun 0xfe |
|
24 |
|
|
25 |
enum USBMSDMode { |
|
26 |
USB_MSDM_CBW, /* Command Block. */ |
|
27 |
USB_MSDM_DATAOUT, /* Tranfer data to device. */ |
|
28 |
USB_MSDM_DATAIN, /* Transfer data from device. */ |
|
29 |
USB_MSDM_CSW /* Command Status. */ |
|
30 |
}; |
|
31 |
|
|
32 |
typedef struct { |
|
33 |
USBDevice dev; |
|
34 |
enum USBMSDMode mode; |
|
35 |
uint32_t data_len; |
|
36 |
uint32_t tag; |
|
37 |
SCSIDevice *scsi_dev; |
|
38 |
int result; |
|
39 |
} MSDState; |
|
40 |
|
|
41 |
static const uint8_t qemu_msd_dev_descriptor[] = { |
|
42 |
0x12, /* u8 bLength; */ |
|
43 |
0x01, /* u8 bDescriptorType; Device */ |
|
44 |
0x10, 0x00, /* u16 bcdUSB; v1.0 */ |
|
45 |
|
|
46 |
0x00, /* u8 bDeviceClass; */ |
|
47 |
0x00, /* u8 bDeviceSubClass; */ |
|
48 |
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ |
|
49 |
0x08, /* u8 bMaxPacketSize0; 8 Bytes */ |
|
50 |
|
|
51 |
/* Vendor and product id are arbitrary. */ |
|
52 |
0x00, 0x00, /* u16 idVendor; */ |
|
53 |
0x00, 0x00, /* u16 idProduct; */ |
|
54 |
0x00, 0x00, /* u16 bcdDevice */ |
|
55 |
|
|
56 |
0x01, /* u8 iManufacturer; */ |
|
57 |
0x02, /* u8 iProduct; */ |
|
58 |
0x03, /* u8 iSerialNumber; */ |
|
59 |
0x01 /* u8 bNumConfigurations; */ |
|
60 |
}; |
|
61 |
|
|
62 |
static const uint8_t qemu_msd_config_descriptor[] = { |
|
63 |
|
|
64 |
/* one configuration */ |
|
65 |
0x09, /* u8 bLength; */ |
|
66 |
0x02, /* u8 bDescriptorType; Configuration */ |
|
67 |
0x20, 0x00, /* u16 wTotalLength; */ |
|
68 |
0x01, /* u8 bNumInterfaces; (1) */ |
|
69 |
0x01, /* u8 bConfigurationValue; */ |
|
70 |
0x00, /* u8 iConfiguration; */ |
|
71 |
0xc0, /* u8 bmAttributes; |
|
72 |
Bit 7: must be set, |
|
73 |
6: Self-powered, |
|
74 |
5: Remote wakeup, |
|
75 |
4..0: resvd */ |
|
76 |
0x00, /* u8 MaxPower; */ |
|
77 |
|
|
78 |
/* one interface */ |
|
79 |
0x09, /* u8 if_bLength; */ |
|
80 |
0x04, /* u8 if_bDescriptorType; Interface */ |
|
81 |
0x00, /* u8 if_bInterfaceNumber; */ |
|
82 |
0x00, /* u8 if_bAlternateSetting; */ |
|
83 |
0x02, /* u8 if_bNumEndpoints; */ |
|
84 |
0x08, /* u8 if_bInterfaceClass; MASS STORAGE */ |
|
85 |
0x06, /* u8 if_bInterfaceSubClass; SCSI */ |
|
86 |
0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ |
|
87 |
0x00, /* u8 if_iInterface; */ |
|
88 |
|
|
89 |
/* Bulk-In endpoint */ |
|
90 |
0x07, /* u8 ep_bLength; */ |
|
91 |
0x05, /* u8 ep_bDescriptorType; Endpoint */ |
|
92 |
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ |
|
93 |
0x02, /* u8 ep_bmAttributes; Bulk */ |
|
94 |
0x40, 0x00, /* u16 ep_wMaxPacketSize; */ |
|
95 |
0x00, /* u8 ep_bInterval; */ |
|
96 |
|
|
97 |
/* Bulk-Out endpoint */ |
|
98 |
0x07, /* u8 ep_bLength; */ |
|
99 |
0x05, /* u8 ep_bDescriptorType; Endpoint */ |
|
100 |
0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ |
|
101 |
0x02, /* u8 ep_bmAttributes; Bulk */ |
|
102 |
0x40, 0x00, /* u16 ep_wMaxPacketSize; */ |
|
103 |
0x00 /* u8 ep_bInterval; */ |
|
104 |
}; |
|
105 |
|
|
106 |
static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) |
|
107 |
{ |
|
108 |
MSDState *s = (MSDState *)opaque; |
|
109 |
|
|
110 |
DPRINTF("Command complete\n"); |
|
111 |
s->result = fail; |
|
112 |
s->mode = USB_MSDM_CSW; |
|
113 |
} |
|
114 |
|
|
115 |
static void usb_msd_handle_reset(USBDevice *dev, int destroy) |
|
116 |
{ |
|
117 |
MSDState *s = (MSDState *)dev; |
|
118 |
|
|
119 |
DPRINTF("Reset\n"); |
|
120 |
s->mode = USB_MSDM_CBW; |
|
121 |
if (destroy) { |
|
122 |
scsi_disk_destroy(s->scsi_dev); |
|
123 |
qemu_free(s); |
|
124 |
} |
|
125 |
} |
|
126 |
|
|
127 |
static int usb_msd_handle_control(USBDevice *dev, int request, int value, |
|
128 |
int index, int length, uint8_t *data) |
|
129 |
{ |
|
130 |
MSDState *s = (MSDState *)dev; |
|
131 |
int ret = 0; |
|
132 |
|
|
133 |
switch (request) { |
|
134 |
case DeviceRequest | USB_REQ_GET_STATUS: |
|
135 |
data[0] = (1 << USB_DEVICE_SELF_POWERED) | |
Also available in: Unified diff