Revision 29c74f76
b/hw/usb-msd.c | ||
---|---|---|
43 | 43 |
enum USBMSDMode mode; |
44 | 44 |
uint32_t scsi_len; |
45 | 45 |
uint8_t *scsi_buf; |
46 |
uint32_t usb_len; |
|
47 |
uint8_t *usb_buf; |
|
48 | 46 |
uint32_t data_len; |
49 | 47 |
uint32_t residue; |
50 | 48 |
uint32_t tag; |
... | ... | |
176 | 174 |
.str = desc_strings, |
177 | 175 |
}; |
178 | 176 |
|
179 |
static void usb_msd_copy_data(MSDState *s) |
|
177 |
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
|
180 | 178 |
{ |
181 | 179 |
uint32_t len; |
182 |
len = s->usb_len;
|
|
180 |
len = p->iov.size - p->result;
|
|
183 | 181 |
if (len > s->scsi_len) |
184 | 182 |
len = s->scsi_len; |
185 |
if (s->mode == USB_MSDM_DATAIN) { |
|
186 |
memcpy(s->usb_buf, s->scsi_buf, len); |
|
187 |
} else { |
|
188 |
memcpy(s->scsi_buf, s->usb_buf, len); |
|
189 |
} |
|
190 |
s->usb_len -= len; |
|
183 |
usb_packet_copy(p, s->scsi_buf, len); |
|
191 | 184 |
s->scsi_len -= len; |
192 |
s->usb_buf += len; |
|
193 | 185 |
s->scsi_buf += len; |
194 | 186 |
s->data_len -= len; |
195 | 187 |
if (s->scsi_len == 0 || s->data_len == 0) { |
... | ... | |
221 | 213 |
s->scsi_len = len; |
222 | 214 |
s->scsi_buf = scsi_req_get_buf(req); |
223 | 215 |
if (p) { |
224 |
usb_msd_copy_data(s); |
|
225 |
if (s->packet && s->usb_len == 0) {
|
|
226 |
p->result = p->iov.size;
|
|
216 |
usb_msd_copy_data(s, p);
|
|
217 |
p = s->packet;
|
|
218 |
if (p && p->result == p->iov.size) {
|
|
227 | 219 |
/* Set s->packet to NULL before calling usb_packet_complete |
228 | 220 |
because another request may be issued before |
229 | 221 |
usb_packet_complete returns. */ |
... | ... | |
250 | 242 |
s->mode = USB_MSDM_CBW; |
251 | 243 |
} else { |
252 | 244 |
if (s->data_len) { |
253 |
s->data_len -= s->usb_len; |
|
254 |
if (s->mode == USB_MSDM_DATAIN) { |
|
255 |
memset(s->usb_buf, 0, s->usb_len); |
|
256 |
} |
|
257 |
s->usb_len = 0; |
|
245 |
int len = (p->iov.size - p->result); |
|
246 |
usb_packet_skip(p, len); |
|
247 |
s->data_len -= len; |
|
258 | 248 |
} |
259 | 249 |
if (s->data_len == 0) { |
260 | 250 |
s->mode = USB_MSDM_CSW; |
261 | 251 |
} |
262 |
p->result = p->iov.size; |
|
263 | 252 |
} |
264 | 253 |
s->packet = NULL; |
265 | 254 |
usb_packet_complete(&s->dev, p); |
... | ... | |
345 | 334 |
int ret = 0; |
346 | 335 |
struct usb_msd_cbw cbw; |
347 | 336 |
uint8_t devep = p->devep; |
348 |
uint8_t *data = p->iov.iov[0].iov_base; |
|
349 |
int len = p->iov.iov[0].iov_len; |
|
350 | 337 |
|
351 |
assert(p->iov.niov == 1); /* temporary */ |
|
352 | 338 |
switch (p->pid) { |
353 | 339 |
case USB_TOKEN_OUT: |
354 | 340 |
if (devep != 2) |
... | ... | |
356 | 342 |
|
357 | 343 |
switch (s->mode) { |
358 | 344 |
case USB_MSDM_CBW: |
359 |
if (len != 31) {
|
|
345 |
if (p->iov.size != 31) {
|
|
360 | 346 |
fprintf(stderr, "usb-msd: Bad CBW size"); |
361 | 347 |
goto fail; |
362 | 348 |
} |
363 |
memcpy(&cbw, data, 31);
|
|
349 |
usb_packet_copy(p, &cbw, 31);
|
|
364 | 350 |
if (le32_to_cpu(cbw.sig) != 0x43425355) { |
365 | 351 |
fprintf(stderr, "usb-msd: Bad signature %08x\n", |
366 | 352 |
le32_to_cpu(cbw.sig)); |
... | ... | |
391 | 377 |
if (s->mode != USB_MSDM_CSW && s->residue == 0) { |
392 | 378 |
scsi_req_continue(s->req); |
393 | 379 |
} |
394 |
ret = len;
|
|
380 |
ret = p->result;
|
|
395 | 381 |
break; |
396 | 382 |
|
397 | 383 |
case USB_MSDM_DATAOUT: |
398 |
DPRINTF("Data out %d/%d\n", len, s->data_len);
|
|
399 |
if (len > s->data_len)
|
|
384 |
DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
|
|
385 |
if (p->iov.size > s->data_len) {
|
|
400 | 386 |
goto fail; |
387 |
} |
|
401 | 388 |
|
402 |
s->usb_buf = data; |
|
403 |
s->usb_len = len; |
|
404 | 389 |
if (s->scsi_len) { |
405 |
usb_msd_copy_data(s); |
|
390 |
usb_msd_copy_data(s, p);
|
|
406 | 391 |
} |
407 |
if (s->residue && s->usb_len) { |
|
408 |
s->data_len -= s->usb_len; |
|
409 |
if (s->data_len == 0) |
|
410 |
s->mode = USB_MSDM_CSW; |
|
411 |
s->usb_len = 0; |
|
392 |
if (s->residue) { |
|
393 |
int len = p->iov.size - p->result; |
|
394 |
if (len) { |
|
395 |
usb_packet_skip(p, len); |
|
396 |
s->data_len -= len; |
|
397 |
if (s->data_len == 0) { |
|
398 |
s->mode = USB_MSDM_CSW; |
|
399 |
} |
|
400 |
} |
|
412 | 401 |
} |
413 |
if (s->usb_len) {
|
|
402 |
if (p->result < p->iov.size) {
|
|
414 | 403 |
DPRINTF("Deferring packet %p\n", p); |
415 | 404 |
s->packet = p; |
416 | 405 |
ret = USB_RET_ASYNC; |
417 | 406 |
} else { |
418 |
ret = len;
|
|
407 |
ret = p->result;
|
|
419 | 408 |
} |
420 | 409 |
break; |
421 | 410 |
|
422 | 411 |
default: |
423 |
DPRINTF("Unexpected write (len %d)\n", len);
|
|
412 |
DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
|
|
424 | 413 |
goto fail; |
425 | 414 |
} |
426 | 415 |
break; |
... | ... | |
431 | 420 |
|
432 | 421 |
switch (s->mode) { |
433 | 422 |
case USB_MSDM_DATAOUT: |
434 |
if (s->data_len != 0 || len < 13)
|
|
423 |
if (s->data_len != 0 || p->iov.size < 13) {
|
|
435 | 424 |
goto fail; |
425 |
} |
|
436 | 426 |
/* Waiting for SCSI write to complete. */ |
437 | 427 |
s->packet = p; |
438 | 428 |
ret = USB_RET_ASYNC; |
439 | 429 |
break; |
440 | 430 |
|
441 | 431 |
case USB_MSDM_CSW: |
442 |
DPRINTF("Command status %d tag 0x%x, len %d\n", |
|
443 |
s->result, s->tag, len);
|
|
444 |
if (len < 13)
|
|
432 |
DPRINTF("Command status %d tag 0x%x, len %zd\n",
|
|
433 |
s->result, s->tag, p->iov.size);
|
|
434 |
if (p->iov.size < 13) {
|
|
445 | 435 |
goto fail; |
436 |
} |
|
446 | 437 |
|
447 | 438 |
usb_msd_send_status(s, p); |
448 | 439 |
s->mode = USB_MSDM_CBW; |
... | ... | |
450 | 441 |
break; |
451 | 442 |
|
452 | 443 |
case USB_MSDM_DATAIN: |
453 |
DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len); |
|
454 |
if (len > s->data_len) |
|
455 |
len = s->data_len; |
|
456 |
s->usb_buf = data; |
|
457 |
s->usb_len = len; |
|
444 |
DPRINTF("Data in %zd/%d, scsi_len %d\n", |
|
445 |
p->iov.size, s->data_len, s->scsi_len); |
|
458 | 446 |
if (s->scsi_len) { |
459 |
usb_msd_copy_data(s); |
|
447 |
usb_msd_copy_data(s, p);
|
|
460 | 448 |
} |
461 |
if (s->residue && s->usb_len) { |
|
462 |
s->data_len -= s->usb_len; |
|
463 |
memset(s->usb_buf, 0, s->usb_len); |
|
464 |
if (s->data_len == 0) |
|
465 |
s->mode = USB_MSDM_CSW; |
|
466 |
s->usb_len = 0; |
|
449 |
if (s->residue) { |
|
450 |
int len = p->iov.size - p->result; |
|
451 |
if (len) { |
|
452 |
usb_packet_skip(p, len); |
|
453 |
s->data_len -= len; |
|
454 |
if (s->data_len == 0) { |
|
455 |
s->mode = USB_MSDM_CSW; |
|
456 |
} |
|
457 |
} |
|
467 | 458 |
} |
468 |
if (s->usb_len) {
|
|
459 |
if (p->result < p->iov.size) {
|
|
469 | 460 |
DPRINTF("Deferring packet %p\n", p); |
470 | 461 |
s->packet = p; |
471 | 462 |
ret = USB_RET_ASYNC; |
472 | 463 |
} else { |
473 |
ret = len;
|
|
464 |
ret = p->result;
|
|
474 | 465 |
} |
475 | 466 |
break; |
476 | 467 |
|
477 | 468 |
default: |
478 |
DPRINTF("Unexpected read (len %d)\n", len);
|
|
469 |
DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
|
|
479 | 470 |
goto fail; |
480 | 471 |
} |
481 | 472 |
break; |
Also available in: Unified diff