Commit 4d611c9a2f4c5d9080d8b6a6f0d7431233cd56f9
1 parent
4ca9c76f
SCSI and USB async IO support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2107 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
14 changed files
with
746 additions
and
293 deletions
hw/esp.c
| @@ -62,6 +62,11 @@ struct ESPState { | @@ -62,6 +62,11 @@ struct ESPState { | ||
| 62 | uint8_t cmdbuf[TI_BUFSZ]; | 62 | uint8_t cmdbuf[TI_BUFSZ]; |
| 63 | int cmdlen; | 63 | int cmdlen; |
| 64 | int do_cmd; | 64 | int do_cmd; |
| 65 | + | ||
| 66 | + uint32_t dma_left; | ||
| 67 | + uint8_t async_buf[TARGET_PAGE_SIZE]; | ||
| 68 | + uint32_t async_ptr; | ||
| 69 | + uint32_t async_len; | ||
| 65 | }; | 70 | }; |
| 66 | 71 | ||
| 67 | #define STAT_DO 0x00 | 72 | #define STAT_DO 0x00 |
| @@ -72,6 +77,8 @@ struct ESPState { | @@ -72,6 +77,8 @@ struct ESPState { | ||
| 72 | #define STAT_MO 0x07 | 77 | #define STAT_MO 0x07 |
| 73 | 78 | ||
| 74 | #define STAT_TC 0x10 | 79 | #define STAT_TC 0x10 |
| 80 | +#define STAT_PE 0x20 | ||
| 81 | +#define STAT_GE 0x40 | ||
| 75 | #define STAT_IN 0x80 | 82 | #define STAT_IN 0x80 |
| 76 | 83 | ||
| 77 | #define INTR_FC 0x08 | 84 | #define INTR_FC 0x08 |
| @@ -195,26 +202,85 @@ static void write_response(ESPState *s) | @@ -195,26 +202,85 @@ static void write_response(ESPState *s) | ||
| 195 | 202 | ||
| 196 | } | 203 | } |
| 197 | 204 | ||
| 198 | -static void esp_command_complete(void *opaque, uint32_t tag, int sense) | 205 | +static void esp_do_dma(ESPState *s) |
| 206 | +{ | ||
| 207 | + uint32_t dmaptr, minlen, len, from, to; | ||
| 208 | + int to_device; | ||
| 209 | + dmaptr = iommu_translate(s->espdmaregs[1]); | ||
| 210 | + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; | ||
| 211 | + from = s->espdmaregs[1]; | ||
| 212 | + minlen = s->dma_left; | ||
| 213 | + to = from + minlen; | ||
| 214 | + dmaptr = iommu_translate(s->espdmaregs[1]); | ||
| 215 | + if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { | ||
| 216 | + len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); | ||
| 217 | + } else { | ||
| 218 | + len = to - from; | ||
| 219 | + } | ||
| 220 | + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); | ||
| 221 | + s->espdmaregs[1] += len; | ||
| 222 | + if (s->do_cmd) { | ||
| 223 | + s->ti_size -= len; | ||
| 224 | + DPRINTF("command len %d + %d\n", s->cmdlen, len); | ||
| 225 | + cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); | ||
| 226 | + s->ti_size = 0; | ||
| 227 | + s->cmdlen = 0; | ||
| 228 | + s->do_cmd = 0; | ||
| 229 | + do_cmd(s, s->cmdbuf); | ||
| 230 | + return; | ||
| 231 | + } else { | ||
| 232 | + s->async_len = len; | ||
| 233 | + s->dma_left -= len; | ||
| 234 | + if (to_device) { | ||
| 235 | + s->async_ptr = -1; | ||
| 236 | + cpu_physical_memory_read(dmaptr, s->async_buf, len); | ||
| 237 | + scsi_write_data(s->current_dev, s->async_buf, len); | ||
| 238 | + } else { | ||
| 239 | + s->async_ptr = dmaptr; | ||
| 240 | + scsi_read_data(s->current_dev, s->async_buf, len); | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | +} | ||
| 244 | + | ||
| 245 | +static void esp_command_complete(void *opaque, uint32_t reason, int sense) | ||
| 199 | { | 246 | { |
| 200 | ESPState *s = (ESPState *)opaque; | 247 | ESPState *s = (ESPState *)opaque; |
| 201 | 248 | ||
| 202 | - DPRINTF("SCSI Command complete\n"); | ||
| 203 | - if (s->ti_size != 0) | ||
| 204 | - DPRINTF("SCSI command completed unexpectedly\n"); | ||
| 205 | - s->ti_size = 0; | ||
| 206 | - if (sense) | ||
| 207 | - DPRINTF("Command failed\n"); | ||
| 208 | - s->sense = sense; | ||
| 209 | - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | 249 | + s->ti_size -= s->async_len; |
| 250 | + s->espdmaregs[1] += s->async_len; | ||
| 251 | + if (s->async_ptr != (uint32_t)-1) { | ||
| 252 | + cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len); | ||
| 253 | + } | ||
| 254 | + if (reason == SCSI_REASON_DONE) { | ||
| 255 | + DPRINTF("SCSI Command complete\n"); | ||
| 256 | + if (s->ti_size != 0) | ||
| 257 | + DPRINTF("SCSI command completed unexpectedly\n"); | ||
| 258 | + s->ti_size = 0; | ||
| 259 | + if (sense) | ||
| 260 | + DPRINTF("Command failed\n"); | ||
| 261 | + s->sense = sense; | ||
| 262 | + } else { | ||
| 263 | + DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); | ||
| 264 | + } | ||
| 265 | + if (s->dma_left) { | ||
| 266 | + esp_do_dma(s); | ||
| 267 | + } else { | ||
| 268 | + if (s->ti_size) { | ||
| 269 | + s->rregs[4] |= STAT_IN | STAT_TC; | ||
| 270 | + } else { | ||
| 271 | + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | ||
| 272 | + } | ||
| 273 | + s->rregs[5] = INTR_BS; | ||
| 274 | + s->rregs[6] = 0; | ||
| 275 | + s->rregs[7] = 0; | ||
| 276 | + s->espdmaregs[0] |= DMA_INTR; | ||
| 277 | + pic_set_irq(s->irq, 1); | ||
| 278 | + } | ||
| 210 | } | 279 | } |
| 211 | 280 | ||
| 212 | static void handle_ti(ESPState *s) | 281 | static void handle_ti(ESPState *s) |
| 213 | { | 282 | { |
| 214 | - uint32_t dmaptr, dmalen, minlen, len, from, to; | ||
| 215 | - unsigned int i; | ||
| 216 | - int to_device; | ||
| 217 | - uint8_t buf[TARGET_PAGE_SIZE]; | 283 | + uint32_t dmalen, minlen; |
| 218 | 284 | ||
| 219 | dmalen = s->wregs[0] | (s->wregs[1] << 8); | 285 | dmalen = s->wregs[0] | (s->wregs[1] << 8); |
| 220 | if (dmalen==0) { | 286 | if (dmalen==0) { |
| @@ -227,47 +293,9 @@ static void handle_ti(ESPState *s) | @@ -227,47 +293,9 @@ static void handle_ti(ESPState *s) | ||
| 227 | minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; | 293 | minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; |
| 228 | DPRINTF("Transfer Information len %d\n", minlen); | 294 | DPRINTF("Transfer Information len %d\n", minlen); |
| 229 | if (s->dma) { | 295 | if (s->dma) { |
| 230 | - dmaptr = iommu_translate(s->espdmaregs[1]); | ||
| 231 | - /* Check if the transfer writes to to reads from the device. */ | ||
| 232 | - to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; | ||
| 233 | - DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", | ||
| 234 | - to_device ? 'r': 'w', dmaptr, s->ti_size); | ||
| 235 | - from = s->espdmaregs[1]; | ||
| 236 | - to = from + minlen; | ||
| 237 | - for (i = 0; i < minlen; i += len, from += len) { | ||
| 238 | - dmaptr = iommu_translate(s->espdmaregs[1] + i); | ||
| 239 | - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { | ||
| 240 | - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); | ||
| 241 | - } else { | ||
| 242 | - len = to - from; | ||
| 243 | - } | ||
| 244 | - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); | ||
| 245 | - s->ti_size -= len; | ||
| 246 | - if (s->do_cmd) { | ||
| 247 | - DPRINTF("command len %d + %d\n", s->cmdlen, len); | ||
| 248 | - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); | ||
| 249 | - s->ti_size = 0; | ||
| 250 | - s->cmdlen = 0; | ||
| 251 | - s->do_cmd = 0; | ||
| 252 | - do_cmd(s, s->cmdbuf); | ||
| 253 | - return; | ||
| 254 | - } else { | ||
| 255 | - if (to_device) { | ||
| 256 | - cpu_physical_memory_read(dmaptr, buf, len); | ||
| 257 | - scsi_write_data(s->current_dev, buf, len); | ||
| 258 | - } else { | ||
| 259 | - scsi_read_data(s->current_dev, buf, len); | ||
| 260 | - cpu_physical_memory_write(dmaptr, buf, len); | ||
| 261 | - } | ||
| 262 | - } | ||
| 263 | - } | ||
| 264 | - if (s->ti_size) { | ||
| 265 | - s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); | ||
| 266 | - } | ||
| 267 | - s->rregs[5] = INTR_BS; | ||
| 268 | - s->rregs[6] = 0; | ||
| 269 | - s->rregs[7] = 0; | ||
| 270 | - s->espdmaregs[0] |= DMA_INTR; | 296 | + s->dma_left = minlen; |
| 297 | + s->rregs[4] &= ~STAT_TC; | ||
| 298 | + esp_do_dma(s); | ||
| 271 | } else if (s->do_cmd) { | 299 | } else if (s->do_cmd) { |
| 272 | DPRINTF("command len %d\n", s->cmdlen); | 300 | DPRINTF("command len %d\n", s->cmdlen); |
| 273 | s->ti_size = 0; | 301 | s->ti_size = 0; |
| @@ -276,7 +304,6 @@ static void handle_ti(ESPState *s) | @@ -276,7 +304,6 @@ static void handle_ti(ESPState *s) | ||
| 276 | do_cmd(s, s->cmdbuf); | 304 | do_cmd(s, s->cmdbuf); |
| 277 | return; | 305 | return; |
| 278 | } | 306 | } |
| 279 | - pic_set_irq(s->irq, 1); | ||
| 280 | } | 307 | } |
| 281 | 308 | ||
| 282 | static void esp_reset(void *opaque) | 309 | static void esp_reset(void *opaque) |
| @@ -320,8 +347,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | @@ -320,8 +347,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | ||
| 320 | break; | 347 | break; |
| 321 | case 5: | 348 | case 5: |
| 322 | // interrupt | 349 | // interrupt |
| 323 | - // Clear status bits except TC | ||
| 324 | - s->rregs[4] &= STAT_TC; | 350 | + // Clear interrupt/error status bits |
| 351 | + s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); | ||
| 325 | pic_set_irq(s->irq, 0); | 352 | pic_set_irq(s->irq, 0); |
| 326 | s->espdmaregs[0] &= ~DMA_INTR; | 353 | s->espdmaregs[0] &= ~DMA_INTR; |
| 327 | break; | 354 | break; |
| @@ -342,6 +369,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | @@ -342,6 +369,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
| 342 | case 0: | 369 | case 0: |
| 343 | case 1: | 370 | case 1: |
| 344 | s->rregs[saddr] = val; | 371 | s->rregs[saddr] = val; |
| 372 | + s->rregs[4] &= ~STAT_TC; | ||
| 345 | break; | 373 | break; |
| 346 | case 2: | 374 | case 2: |
| 347 | // FIFO | 375 | // FIFO |
hw/lsi53c895a.c
| @@ -152,6 +152,9 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) | @@ -152,6 +152,9 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) | ||
| 152 | /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ | 152 | /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ |
| 153 | #define LSI_MAX_DEVS 7 | 153 | #define LSI_MAX_DEVS 7 |
| 154 | 154 | ||
| 155 | +/* Size of internal DMA buffer for async IO requests. */ | ||
| 156 | +#define LSI_DMA_BLOCK_SIZE 0x10000 | ||
| 157 | + | ||
| 155 | typedef struct { | 158 | typedef struct { |
| 156 | PCIDevice pci_dev; | 159 | PCIDevice pci_dev; |
| 157 | int mmio_io_addr; | 160 | int mmio_io_addr; |
| @@ -162,7 +165,9 @@ typedef struct { | @@ -162,7 +165,9 @@ typedef struct { | ||
| 162 | int carry; /* ??? Should this be an a visible register somewhere? */ | 165 | int carry; /* ??? Should this be an a visible register somewhere? */ |
| 163 | int sense; | 166 | int sense; |
| 164 | uint8_t msg; | 167 | uint8_t msg; |
| 165 | - /* Nonzero if a Wait Reselect instruction has been issued. */ | 168 | + /* 0 if SCRIPTS are running or stopped. |
| 169 | + * 1 if a Wait Reselect instruction has been issued. | ||
| 170 | + * 2 if a DMA operation is in progress. */ | ||
| 166 | int waiting; | 171 | int waiting; |
| 167 | SCSIDevice *scsi_dev[LSI_MAX_DEVS]; | 172 | SCSIDevice *scsi_dev[LSI_MAX_DEVS]; |
| 168 | SCSIDevice *current_dev; | 173 | SCSIDevice *current_dev; |
| @@ -226,6 +231,7 @@ typedef struct { | @@ -226,6 +231,7 @@ typedef struct { | ||
| 226 | uint32_t csbc; | 231 | uint32_t csbc; |
| 227 | uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ | 232 | uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ |
| 228 | 233 | ||
| 234 | + uint8_t dma_buf[LSI_DMA_BLOCK_SIZE]; | ||
| 229 | /* Script ram is stored as 32-bit words in host byteorder. */ | 235 | /* Script ram is stored as 32-bit words in host byteorder. */ |
| 230 | uint32_t script_ram[2048]; | 236 | uint32_t script_ram[2048]; |
| 231 | } LSIState; | 237 | } LSIState; |
| @@ -295,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) | @@ -295,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) | ||
| 295 | 301 | ||
| 296 | static uint8_t lsi_reg_readb(LSIState *s, int offset); | 302 | static uint8_t lsi_reg_readb(LSIState *s, int offset); |
| 297 | static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); | 303 | static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); |
| 304 | +static void lsi_execute_script(LSIState *s); | ||
| 298 | 305 | ||
| 299 | static inline uint32_t read_dword(LSIState *s, uint32_t addr) | 306 | static inline uint32_t read_dword(LSIState *s, uint32_t addr) |
| 300 | { | 307 | { |
| @@ -402,21 +409,20 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) | @@ -402,21 +409,20 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) | ||
| 402 | lsi_set_phase(s, new_phase); | 409 | lsi_set_phase(s, new_phase); |
| 403 | } | 410 | } |
| 404 | 411 | ||
| 412 | +/* Initiate a SCSI layer data transfer. */ | ||
| 405 | static void lsi_do_dma(LSIState *s, int out) | 413 | static void lsi_do_dma(LSIState *s, int out) |
| 406 | { | 414 | { |
| 407 | - uint8_t buf[TARGET_PAGE_SIZE]; | ||
| 408 | - uint32_t addr; | ||
| 409 | uint32_t count; | 415 | uint32_t count; |
| 410 | - int n; | ||
| 411 | 416 | ||
| 412 | count = s->dbc; | 417 | count = s->dbc; |
| 413 | - addr = s->dnad; | ||
| 414 | - DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in", | 418 | + if (count > LSI_DMA_BLOCK_SIZE) |
| 419 | + count = LSI_DMA_BLOCK_SIZE; | ||
| 420 | + DPRINTF("DMA addr=0x%08x len=%d avail=%d\n", | ||
| 415 | addr, count, s->data_len); | 421 | addr, count, s->data_len); |
| 416 | /* ??? Too long transfers are truncated. Don't know if this is the | 422 | /* ??? Too long transfers are truncated. Don't know if this is the |
| 417 | correct behavior. */ | 423 | correct behavior. */ |
| 418 | if (count > s->data_len) { | 424 | if (count > s->data_len) { |
| 419 | - /* If the DMA length is greater then the device data length then | 425 | + /* If the DMA length is greater than the device data length then |
| 420 | a phase mismatch will occur. */ | 426 | a phase mismatch will occur. */ |
| 421 | count = s->data_len; | 427 | count = s->data_len; |
| 422 | s->dbc = count; | 428 | s->dbc = count; |
| @@ -426,20 +432,47 @@ static void lsi_do_dma(LSIState *s, int out) | @@ -426,20 +432,47 @@ static void lsi_do_dma(LSIState *s, int out) | ||
| 426 | s->csbc += count; | 432 | s->csbc += count; |
| 427 | 433 | ||
| 428 | /* ??? Set SFBR to first data byte. */ | 434 | /* ??? Set SFBR to first data byte. */ |
| 429 | - while (count) { | ||
| 430 | - n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; | ||
| 431 | - if (out) { | ||
| 432 | - cpu_physical_memory_read(addr, buf, n); | ||
| 433 | - scsi_write_data(s->current_dev, buf, n); | ||
| 434 | - } else { | ||
| 435 | - scsi_read_data(s->current_dev, buf, n); | ||
| 436 | - cpu_physical_memory_write(addr, buf, n); | ||
| 437 | - } | ||
| 438 | - addr += n; | ||
| 439 | - count -= n; | 435 | + if ((s->sstat1 & PHASE_MASK) == PHASE_DO) { |
| 436 | + cpu_physical_memory_read(s->dnad, s->dma_buf, count); | ||
| 437 | + scsi_write_data(s->current_dev, s->dma_buf, count); | ||
| 438 | + } else { | ||
| 439 | + scsi_read_data(s->current_dev, s->dma_buf, count); | ||
| 440 | } | 440 | } |
| 441 | + /* If the DMA did not complete then suspend execution. */ | ||
| 442 | + if (s->dbc) | ||
| 443 | + s->waiting = 2; | ||
| 441 | } | 444 | } |
| 442 | 445 | ||
| 446 | +/* Callback to indicate that the SCSI layer has completed a transfer. */ | ||
| 447 | +static void lsi_command_complete(void *opaque, uint32_t reason, int sense) | ||
| 448 | +{ | ||
| 449 | + LSIState *s = (LSIState *)opaque; | ||
| 450 | + uint32_t count; | ||
| 451 | + int out; | ||
| 452 | + | ||
| 453 | + out = ((s->sstat1 & PHASE_MASK) == PHASE_DO); | ||
| 454 | + count = s->dbc; | ||
| 455 | + if (count > LSI_DMA_BLOCK_SIZE) | ||
| 456 | + count = LSI_DMA_BLOCK_SIZE; | ||
| 457 | + if (!out) | ||
| 458 | + cpu_physical_memory_write(s->dnad, s->dma_buf, count); | ||
| 459 | + s->dnad += count; | ||
| 460 | + s->dbc -= count; | ||
| 461 | + | ||
| 462 | + if (reason == SCSI_REASON_DONE) { | ||
| 463 | + DPRINTF("Command complete sense=%d\n", sense); | ||
| 464 | + s->sense = sense; | ||
| 465 | + lsi_set_phase(s, PHASE_ST); | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + if (s->dbc) { | ||
| 469 | + lsi_do_dma(s, out); | ||
| 470 | + } else if (s->waiting == 2) { | ||
| 471 | + /* Restart SCRIPTS execution. */ | ||
| 472 | + s->waiting = 0; | ||
| 473 | + lsi_execute_script(s); | ||
| 474 | + } | ||
| 475 | +} | ||
| 443 | 476 | ||
| 444 | static void lsi_do_command(LSIState *s) | 477 | static void lsi_do_command(LSIState *s) |
| 445 | { | 478 | { |
| @@ -461,15 +494,6 @@ static void lsi_do_command(LSIState *s) | @@ -461,15 +494,6 @@ static void lsi_do_command(LSIState *s) | ||
| 461 | } | 494 | } |
| 462 | } | 495 | } |
| 463 | 496 | ||
| 464 | -static void lsi_command_complete(void *opaque, uint32_t tag, int sense) | ||
| 465 | -{ | ||
| 466 | - LSIState *s = (LSIState *)opaque; | ||
| 467 | - | ||
| 468 | - DPRINTF("Command complete sense=%d\n", sense); | ||
| 469 | - s->sense = sense; | ||
| 470 | - lsi_set_phase(s, PHASE_ST); | ||
| 471 | -} | ||
| 472 | - | ||
| 473 | static void lsi_do_status(LSIState *s) | 497 | static void lsi_do_status(LSIState *s) |
| 474 | { | 498 | { |
| 475 | DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); | 499 | DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); |
| @@ -1134,7 +1158,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) | @@ -1134,7 +1158,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) | ||
| 1134 | s->istat0 &= ~LSI_ISTAT0_INTF; | 1158 | s->istat0 &= ~LSI_ISTAT0_INTF; |
| 1135 | lsi_update_irq(s); | 1159 | lsi_update_irq(s); |
| 1136 | } | 1160 | } |
| 1137 | - if (s->waiting && val & LSI_ISTAT0_SIGP) { | 1161 | + if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) { |
| 1138 | DPRINTF("Woken by SIGP\n"); | 1162 | DPRINTF("Woken by SIGP\n"); |
| 1139 | s->waiting = 0; | 1163 | s->waiting = 0; |
| 1140 | s->dsp = s->dnad; | 1164 | s->dsp = s->dnad; |
hw/scsi-disk.c
| @@ -25,6 +25,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) | @@ -25,6 +25,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) | ||
| 25 | 25 | ||
| 26 | #define SENSE_NO_SENSE 0 | 26 | #define SENSE_NO_SENSE 0 |
| 27 | #define SENSE_NOT_READY 2 | 27 | #define SENSE_NOT_READY 2 |
| 28 | +#define SENSE_HARDWARE_ERROR 4 | ||
| 28 | #define SENSE_ILLEGAL_REQUEST 5 | 29 | #define SENSE_ILLEGAL_REQUEST 5 |
| 29 | 30 | ||
| 30 | struct SCSIDevice | 31 | struct SCSIDevice |
| @@ -46,7 +47,13 @@ struct SCSIDevice | @@ -46,7 +47,13 @@ struct SCSIDevice | ||
| 46 | int buf_pos; | 47 | int buf_pos; |
| 47 | int buf_len; | 48 | int buf_len; |
| 48 | int sense; | 49 | int sense; |
| 50 | + BlockDriverAIOCB *aiocb; | ||
| 51 | + /* Data still to be transfered after this request completes. */ | ||
| 52 | + uint8_t *aiodata; | ||
| 53 | + uint32_t aiolen; | ||
| 49 | char buf[512]; | 54 | char buf[512]; |
| 55 | + /* Completion functions may be called from either scsi_{read,write}_data | ||
| 56 | + or from the AIO completion routines. */ | ||
| 50 | scsi_completionfn completion; | 57 | scsi_completionfn completion; |
| 51 | void *opaque; | 58 | void *opaque; |
| 52 | }; | 59 | }; |
| @@ -54,10 +61,49 @@ struct SCSIDevice | @@ -54,10 +61,49 @@ struct SCSIDevice | ||
| 54 | static void scsi_command_complete(SCSIDevice *s, int sense) | 61 | static void scsi_command_complete(SCSIDevice *s, int sense) |
| 55 | { | 62 | { |
| 56 | s->sense = sense; | 63 | s->sense = sense; |
| 57 | - s->completion(s->opaque, s->tag, sense); | 64 | + s->completion(s->opaque, SCSI_REASON_DONE, sense); |
| 58 | } | 65 | } |
| 59 | 66 | ||
| 60 | -/* Read data from a scsi device. Returns nonzero on failure. */ | 67 | +static void scsi_transfer_complete(SCSIDevice *s) |
| 68 | +{ | ||
| 69 | + s->completion(s->opaque, SCSI_REASON_DATA, 0); | ||
| 70 | + s->aiocb = NULL; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +static void scsi_read_complete(void * opaque, int ret) | ||
| 74 | +{ | ||
| 75 | + SCSIDevice *s = (SCSIDevice *)opaque; | ||
| 76 | + | ||
| 77 | + if (ret) { | ||
| 78 | + DPRINTF("IO error\n"); | ||
| 79 | + scsi_command_complete(s, SENSE_HARDWARE_ERROR); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + if (s->aiolen) { | ||
| 83 | + /* Read the remaining data. Full and partial sectors are transferred | ||
| 84 | + separately. */ | ||
| 85 | + scsi_read_data(s, s->aiodata, s->aiolen); | ||
| 86 | + } else { | ||
| 87 | + if (s->buf_len == 0 && s->sector_count == 0) | ||
| 88 | + scsi_command_complete(s, SENSE_NO_SENSE); | ||
| 89 | + else | ||
| 90 | + scsi_transfer_complete(s); | ||
| 91 | + } | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +/* Cancel a pending data transfer. */ | ||
| 95 | +void scsi_cancel_io(SCSIDevice *s) | ||
| 96 | +{ | ||
| 97 | + if (!s->aiocb) { | ||
| 98 | + BADF("Cancel with no pending IO\n"); | ||
| 99 | + return; | ||
| 100 | + } | ||
| 101 | + bdrv_aio_cancel(s->aiocb); | ||
| 102 | + s->aiocb = NULL; | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +/* Read data from a scsi device. Returns nonzero on failure. | ||
| 106 | + The transfer may complete asynchronously. */ | ||
| 61 | int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | 107 | int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) |
| 62 | { | 108 | { |
| 63 | uint32_t n; | 109 | uint32_t n; |
| @@ -84,14 +130,19 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | @@ -84,14 +130,19 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | ||
| 84 | n = s->sector_count; | 130 | n = s->sector_count; |
| 85 | 131 | ||
| 86 | if (n != 0) { | 132 | if (n != 0) { |
| 87 | - bdrv_read(s->bdrv, s->sector, data, n); | ||
| 88 | - data += n * 512; | ||
| 89 | - len -= n * 512; | 133 | + s->aiolen = len - n * 512; |
| 134 | + s->aiodata = data + n * 512; | ||
| 135 | + s->aiocb = bdrv_aio_read(s->bdrv, s->sector, data, n, | ||
| 136 | + scsi_read_complete, s); | ||
| 137 | + if (s->aiocb == NULL) | ||
| 138 | + scsi_command_complete(s, SENSE_HARDWARE_ERROR); | ||
| 90 | s->sector += n; | 139 | s->sector += n; |
| 91 | s->sector_count -= n; | 140 | s->sector_count -= n; |
| 141 | + return 0; | ||
| 92 | } | 142 | } |
| 93 | 143 | ||
| 94 | if (len && s->sector_count) { | 144 | if (len && s->sector_count) { |
| 145 | + /* TODO: Make this use AIO. */ | ||
| 95 | bdrv_read(s->bdrv, s->sector, s->buf, 1); | 146 | bdrv_read(s->bdrv, s->sector, s->buf, 1); |
| 96 | s->sector++; | 147 | s->sector++; |
| 97 | s->sector_count--; | 148 | s->sector_count--; |
| @@ -106,11 +157,53 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | @@ -106,11 +157,53 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) | ||
| 106 | 157 | ||
| 107 | if (s->buf_len == 0 && s->sector_count == 0) | 158 | if (s->buf_len == 0 && s->sector_count == 0) |
| 108 | scsi_command_complete(s, SENSE_NO_SENSE); | 159 | scsi_command_complete(s, SENSE_NO_SENSE); |
| 160 | + else | ||
| 161 | + scsi_transfer_complete(s); | ||
| 109 | 162 | ||
| 110 | return 0; | 163 | return 0; |
| 111 | } | 164 | } |
| 112 | 165 | ||
| 113 | -/* Read data to a scsi device. Returns nonzero on failure. */ | 166 | +static void scsi_write_complete(void * opaque, int ret) |
| 167 | +{ | ||
| 168 | + SCSIDevice *s = (SCSIDevice *)opaque; | ||
| 169 | + | ||
| 170 | + if (ret) { | ||
| 171 | + fprintf(stderr, "scsi-disc: IO write error\n"); | ||
| 172 | + exit(1); | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + if (s->sector_count == 0) | ||
| 176 | + scsi_command_complete(s, SENSE_NO_SENSE); | ||
| 177 | + else | ||
| 178 | + scsi_transfer_complete(s); | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +static uint32_t scsi_write_partial_sector(SCSIDevice *s, uint8_t *data, | ||
| 182 | + uint32_t len) | ||
| 183 | +{ | ||
| 184 | + int n; | ||
| 185 | + | ||
| 186 | + n = 512 - s->buf_len; | ||
| 187 | + if (n > len) | ||
| 188 | + n = len; | ||
| 189 | + | ||
| 190 | + memcpy(s->buf + s->buf_len, data, n); | ||
| 191 | + data += n; | ||
| 192 | + s->buf_len += n; | ||
| 193 | + len -= n; | ||
| 194 | + if (s->buf_len == 512) { | ||
| 195 | + /* A full sector has been accumulated. Write it to disk. */ | ||
| 196 | + /* TODO: Make this use async IO. */ | ||
| 197 | + bdrv_write(s->bdrv, s->sector, s->buf, 1); | ||
| 198 | + s->buf_len = 0; | ||
| 199 | + s->sector++; | ||
| 200 | + s->sector_count--; | ||
| 201 | + } | ||
| 202 | + return n; | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +/* Write data to a scsi device. Returns nonzero on failure. | ||
| 206 | + The transfer may complete asynchronously. */ | ||
| 114 | int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) | 207 | int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) |
| 115 | { | 208 | { |
| 116 | uint32_t n; | 209 | uint32_t n; |
| @@ -125,48 +218,39 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) | @@ -125,48 +218,39 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) | ||
| 125 | return 1; | 218 | return 1; |
| 126 | 219 | ||
| 127 | if (s->buf_len != 0 || len < 512) { | 220 | if (s->buf_len != 0 || len < 512) { |
| 128 | - n = 512 - s->buf_len; | ||
| 129 | - if (n > len) | ||
| 130 | - n = len; | ||
| 131 | - | ||
| 132 | - memcpy(s->buf + s->buf_len, data, n); | ||
| 133 | - data += n; | ||
| 134 | - s->buf_len += n; | 221 | + n = scsi_write_partial_sector(s, data, len); |
| 135 | len -= n; | 222 | len -= n; |
| 136 | - if (s->buf_len == 512) { | ||
| 137 | - /* A full sector has been accumulated. Write it to disk. */ | ||
| 138 | - bdrv_write(s->bdrv, s->sector, s->buf, 1); | ||
| 139 | - s->buf_len = 0; | ||
| 140 | - s->sector++; | ||
| 141 | - s->sector_count--; | ||
| 142 | - } | 223 | + data += n; |
| 143 | } | 224 | } |
| 144 | 225 | ||
| 145 | n = len / 512; | 226 | n = len / 512; |
| 146 | if (n > s->sector_count) | 227 | if (n > s->sector_count) |
| 147 | - n = s->sector_count; | 228 | + return 1; |
| 148 | 229 | ||
| 149 | if (n != 0) { | 230 | if (n != 0) { |
| 150 | - bdrv_write(s->bdrv, s->sector, data, n); | 231 | + s->aiocb = bdrv_aio_write(s->bdrv, s->sector, data, n, |
| 232 | + scsi_write_complete, s); | ||
| 233 | + if (s->aiocb == NULL) | ||
| 234 | + scsi_command_complete(s, SENSE_HARDWARE_ERROR); | ||
| 151 | data += n * 512; | 235 | data += n * 512; |
| 152 | len -= n * 512; | 236 | len -= n * 512; |
| 153 | s->sector += n; | 237 | s->sector += n; |
| 154 | s->sector_count -= n; | 238 | s->sector_count -= n; |
| 155 | } | 239 | } |
| 156 | 240 | ||
| 157 | - if (len >= 512) | ||
| 158 | - return 1; | ||
| 159 | - | ||
| 160 | - if (len && s->sector_count) { | ||
| 161 | - /* Recurse to complete the partial write. */ | ||
| 162 | - return scsi_write_data(s, data, len); | 241 | + if (len) { |
| 242 | + if (s->sector_count == 0) | ||
| 243 | + return 1; | ||
| 244 | + /* Complete a partial write. */ | ||
| 245 | + scsi_write_partial_sector(s, data, len); | ||
| 246 | + } | ||
| 247 | + if (n == 0) { | ||
| 248 | + /* Transfer completes immediately. */ | ||
| 249 | + if (s->sector_count == 0) | ||
| 250 | + scsi_command_complete(s, SENSE_NO_SENSE); | ||
| 251 | + else | ||
| 252 | + scsi_transfer_complete(s); | ||
| 163 | } | 253 | } |
| 164 | - | ||
| 165 | - if (len != 0) | ||
| 166 | - return 1; | ||
| 167 | - | ||
| 168 | - if (s->sector_count == 0) | ||
| 169 | - scsi_command_complete(s, SENSE_NO_SENSE); | ||
| 170 | 254 | ||
| 171 | return 0; | 255 | return 0; |
| 172 | } | 256 | } |
hw/usb-hid.c
| @@ -474,19 +474,18 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | @@ -474,19 +474,18 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | ||
| 474 | return ret; | 474 | return ret; |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | -static int usb_mouse_handle_data(USBDevice *dev, int pid, | ||
| 478 | - uint8_t devep, uint8_t *data, int len) | 477 | +static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) |
| 479 | { | 478 | { |
| 480 | USBMouseState *s = (USBMouseState *)dev; | 479 | USBMouseState *s = (USBMouseState *)dev; |
| 481 | int ret = 0; | 480 | int ret = 0; |
| 482 | 481 | ||
| 483 | - switch(pid) { | 482 | + switch(p->pid) { |
| 484 | case USB_TOKEN_IN: | 483 | case USB_TOKEN_IN: |
| 485 | - if (devep == 1) { | 484 | + if (p->devep == 1) { |
| 486 | if (s->kind == USB_MOUSE) | 485 | if (s->kind == USB_MOUSE) |
| 487 | - ret = usb_mouse_poll(s, data, len); | 486 | + ret = usb_mouse_poll(s, p->data, p->len); |
| 488 | else if (s->kind == USB_TABLET) | 487 | else if (s->kind == USB_TABLET) |
| 489 | - ret = usb_tablet_poll(s, data, len); | 488 | + ret = usb_tablet_poll(s, p->data, p->len); |
| 490 | } else { | 489 | } else { |
| 491 | goto fail; | 490 | goto fail; |
| 492 | } | 491 | } |
hw/usb-hub.c
| @@ -180,8 +180,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | @@ -180,8 +180,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
| 180 | port->wPortStatus &= ~PORT_STAT_LOW_SPEED; | 180 | port->wPortStatus &= ~PORT_STAT_LOW_SPEED; |
| 181 | port->port.dev = dev; | 181 | port->port.dev = dev; |
| 182 | /* send the attach message */ | 182 | /* send the attach message */ |
| 183 | - dev->handle_packet(dev, | ||
| 184 | - USB_MSG_ATTACH, 0, 0, NULL, 0); | 183 | + usb_send_msg(dev, USB_MSG_ATTACH); |
| 185 | } else { | 184 | } else { |
| 186 | dev = port->port.dev; | 185 | dev = port->port.dev; |
| 187 | if (dev) { | 186 | if (dev) { |
| @@ -192,8 +191,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | @@ -192,8 +191,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
| 192 | port->wPortChange |= PORT_STAT_C_ENABLE; | 191 | port->wPortChange |= PORT_STAT_C_ENABLE; |
| 193 | } | 192 | } |
| 194 | /* send the detach message */ | 193 | /* send the detach message */ |
| 195 | - dev->handle_packet(dev, | ||
| 196 | - USB_MSG_DETACH, 0, 0, NULL, 0); | 194 | + usb_send_msg(dev, USB_MSG_DETACH); |
| 197 | port->port.dev = NULL; | 195 | port->port.dev = NULL; |
| 198 | } | 196 | } |
| 199 | } | 197 | } |
| @@ -349,8 +347,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | @@ -349,8 +347,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
| 349 | break; | 347 | break; |
| 350 | case PORT_RESET: | 348 | case PORT_RESET: |
| 351 | if (dev) { | 349 | if (dev) { |
| 352 | - dev->handle_packet(dev, | ||
| 353 | - USB_MSG_RESET, 0, 0, NULL, 0); | 350 | + usb_send_msg(dev, USB_MSG_RESET); |
| 354 | port->wPortChange |= PORT_STAT_C_RESET; | 351 | port->wPortChange |= PORT_STAT_C_RESET; |
| 355 | /* set enable bit */ | 352 | /* set enable bit */ |
| 356 | port->wPortStatus |= PORT_STAT_ENABLE; | 353 | port->wPortStatus |= PORT_STAT_ENABLE; |
| @@ -434,22 +431,21 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | @@ -434,22 +431,21 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, | ||
| 434 | return ret; | 431 | return ret; |
| 435 | } | 432 | } |
| 436 | 433 | ||
| 437 | -static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
| 438 | - uint8_t devep, uint8_t *data, int len) | 434 | +static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) |
| 439 | { | 435 | { |
| 440 | USBHubState *s = (USBHubState *)dev; | 436 | USBHubState *s = (USBHubState *)dev; |
| 441 | int ret; | 437 | int ret; |
| 442 | 438 | ||
| 443 | - switch(pid) { | 439 | + switch(p->pid) { |
| 444 | case USB_TOKEN_IN: | 440 | case USB_TOKEN_IN: |
| 445 | - if (devep == 1) { | 441 | + if (p->devep == 1) { |
| 446 | USBHubPort *port; | 442 | USBHubPort *port; |
| 447 | unsigned int status; | 443 | unsigned int status; |
| 448 | int i, n; | 444 | int i, n; |
| 449 | n = (s->nb_ports + 1 + 7) / 8; | 445 | n = (s->nb_ports + 1 + 7) / 8; |
| 450 | - if (len == 1) { /* FreeBSD workaround */ | 446 | + if (p->len == 1) { /* FreeBSD workaround */ |
| 451 | n = 1; | 447 | n = 1; |
| 452 | - } else if (n > len) { | 448 | + } else if (n > p->len) { |
| 453 | return USB_RET_BABBLE; | 449 | return USB_RET_BABBLE; |
| 454 | } | 450 | } |
| 455 | status = 0; | 451 | status = 0; |
| @@ -460,7 +456,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | @@ -460,7 +456,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
| 460 | } | 456 | } |
| 461 | if (status != 0) { | 457 | if (status != 0) { |
| 462 | for(i = 0; i < n; i++) { | 458 | for(i = 0; i < n; i++) { |
| 463 | - data[i] = status >> (8 * i); | 459 | + p->data[i] = status >> (8 * i); |
| 464 | } | 460 | } |
| 465 | ret = n; | 461 | ret = n; |
| 466 | } else { | 462 | } else { |
| @@ -479,9 +475,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | @@ -479,9 +475,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, | ||
| 479 | return ret; | 475 | return ret; |
| 480 | } | 476 | } |
| 481 | 477 | ||
| 482 | -static int usb_hub_broadcast_packet(USBHubState *s, int pid, | ||
| 483 | - uint8_t devaddr, uint8_t devep, | ||
| 484 | - uint8_t *data, int len) | 478 | +static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p) |
| 485 | { | 479 | { |
| 486 | USBHubPort *port; | 480 | USBHubPort *port; |
| 487 | USBDevice *dev; | 481 | USBDevice *dev; |
| @@ -491,9 +485,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, | @@ -491,9 +485,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, | ||
| 491 | port = &s->ports[i]; | 485 | port = &s->ports[i]; |
| 492 | dev = port->port.dev; | 486 | dev = port->port.dev; |
| 493 | if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { | 487 | if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { |
| 494 | - ret = dev->handle_packet(dev, pid, | ||
| 495 | - devaddr, devep, | ||
| 496 | - data, len); | 488 | + ret = dev->handle_packet(dev, p); |
| 497 | if (ret != USB_RET_NODEV) { | 489 | if (ret != USB_RET_NODEV) { |
| 498 | return ret; | 490 | return ret; |
| 499 | } | 491 | } |
| @@ -502,9 +494,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, | @@ -502,9 +494,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, | ||
| 502 | return USB_RET_NODEV; | 494 | return USB_RET_NODEV; |
| 503 | } | 495 | } |
| 504 | 496 | ||
| 505 | -static int usb_hub_handle_packet(USBDevice *dev, int pid, | ||
| 506 | - uint8_t devaddr, uint8_t devep, | ||
| 507 | - uint8_t *data, int len) | 497 | +static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p) |
| 508 | { | 498 | { |
| 509 | USBHubState *s = (USBHubState *)dev; | 499 | USBHubState *s = (USBHubState *)dev; |
| 510 | 500 | ||
| @@ -513,14 +503,14 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, | @@ -513,14 +503,14 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, | ||
| 513 | #endif | 503 | #endif |
| 514 | if (dev->state == USB_STATE_DEFAULT && | 504 | if (dev->state == USB_STATE_DEFAULT && |
| 515 | dev->addr != 0 && | 505 | dev->addr != 0 && |
| 516 | - devaddr != dev->addr && | ||
| 517 | - (pid == USB_TOKEN_SETUP || | ||
| 518 | - pid == USB_TOKEN_OUT || | ||
| 519 | - pid == USB_TOKEN_IN)) { | 506 | + p->devaddr != dev->addr && |
| 507 | + (p->pid == USB_TOKEN_SETUP || | ||
| 508 | + p->pid == USB_TOKEN_OUT || | ||
| 509 | + p->pid == USB_TOKEN_IN)) { | ||
| 520 | /* broadcast the packet to the devices */ | 510 | /* broadcast the packet to the devices */ |
| 521 | - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); | 511 | + return usb_hub_broadcast_packet(s, p); |
| 522 | } | 512 | } |
| 523 | - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); | 513 | + return usb_generic_handle_packet(dev, p); |
| 524 | } | 514 | } |
| 525 | 515 | ||
| 526 | static void usb_hub_handle_destroy(USBDevice *dev) | 516 | static void usb_hub_handle_destroy(USBDevice *dev) |
hw/usb-msd.c
| @@ -33,9 +33,12 @@ typedef struct { | @@ -33,9 +33,12 @@ typedef struct { | ||
| 33 | USBDevice dev; | 33 | USBDevice dev; |
| 34 | enum USBMSDMode mode; | 34 | enum USBMSDMode mode; |
| 35 | uint32_t data_len; | 35 | uint32_t data_len; |
| 36 | + uint32_t transfer_len; | ||
| 36 | uint32_t tag; | 37 | uint32_t tag; |
| 37 | SCSIDevice *scsi_dev; | 38 | SCSIDevice *scsi_dev; |
| 38 | int result; | 39 | int result; |
| 40 | + /* For async completion. */ | ||
| 41 | + USBPacket *packet; | ||
| 39 | } MSDState; | 42 | } MSDState; |
| 40 | 43 | ||
| 41 | static const uint8_t qemu_msd_dev_descriptor[] = { | 44 | static const uint8_t qemu_msd_dev_descriptor[] = { |
| @@ -103,13 +106,27 @@ static const uint8_t qemu_msd_config_descriptor[] = { | @@ -103,13 +106,27 @@ static const uint8_t qemu_msd_config_descriptor[] = { | ||
| 103 | 0x00 /* u8 ep_bInterval; */ | 106 | 0x00 /* u8 ep_bInterval; */ |
| 104 | }; | 107 | }; |
| 105 | 108 | ||
| 106 | -static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) | 109 | +static void usb_msd_command_complete(void *opaque, uint32_t reason, int fail) |
| 107 | { | 110 | { |
| 108 | MSDState *s = (MSDState *)opaque; | 111 | MSDState *s = (MSDState *)opaque; |
| 109 | - | ||
| 110 | - DPRINTF("Command complete\n"); | ||
| 111 | - s->result = fail; | ||
| 112 | - s->mode = USB_MSDM_CSW; | 112 | + USBPacket *p; |
| 113 | + | ||
| 114 | + s->data_len -= s->transfer_len; | ||
| 115 | + s->transfer_len = 0; | ||
| 116 | + if (reason == SCSI_REASON_DONE) { | ||
| 117 | + DPRINTF("Command complete %d\n", fail); | ||
| 118 | + s->result = fail; | ||
| 119 | + s->mode = USB_MSDM_CSW; | ||
| 120 | + } | ||
| 121 | + if (s->packet) { | ||
| 122 | + /* Set s->packet to NULL before calling usb_packet_complete because | ||
| 123 | + annother request may be issues before usb_packet_complete returns. | ||
| 124 | + */ | ||
| 125 | + DPRINTF("Packet complete %p\n", p); | ||
| 126 | + p = s->packet; | ||
| 127 | + s->packet = NULL; | ||
| 128 | + usb_packet_complete(p); | ||
| 129 | + } | ||
| 113 | } | 130 | } |
| 114 | 131 | ||
| 115 | static void usb_msd_handle_reset(USBDevice *dev) | 132 | static void usb_msd_handle_reset(USBDevice *dev) |
| @@ -250,15 +267,24 @@ struct usb_msd_csw { | @@ -250,15 +267,24 @@ struct usb_msd_csw { | ||
| 250 | uint8_t status; | 267 | uint8_t status; |
| 251 | }; | 268 | }; |
| 252 | 269 | ||
| 253 | -static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, | ||
| 254 | - uint8_t *data, int len) | 270 | +static void usb_msd_cancel_io(USBPacket *p, void *opaque) |
| 271 | +{ | ||
| 272 | + MSDState *s = opaque; | ||
| 273 | + scsi_cancel_io(s->scsi_dev); | ||
| 274 | + s->packet = NULL; | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) | ||
| 255 | { | 278 | { |
| 256 | MSDState *s = (MSDState *)dev; | 279 | MSDState *s = (MSDState *)dev; |
| 257 | int ret = 0; | 280 | int ret = 0; |
| 258 | struct usb_msd_cbw cbw; | 281 | struct usb_msd_cbw cbw; |
| 259 | struct usb_msd_csw csw; | 282 | struct usb_msd_csw csw; |
| 283 | + uint8_t devep = p->devep; | ||
| 284 | + uint8_t *data = p->data; | ||
| 285 | + int len = p->len; | ||
| 260 | 286 | ||
| 261 | - switch (pid) { | 287 | + switch (p->pid) { |
| 262 | case USB_TOKEN_OUT: | 288 | case USB_TOKEN_OUT: |
| 263 | if (devep != 2) | 289 | if (devep != 2) |
| 264 | goto fail; | 290 | goto fail; |
| @@ -300,13 +326,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, | @@ -300,13 +326,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, | ||
| 300 | if (len > s->data_len) | 326 | if (len > s->data_len) |
| 301 | goto fail; | 327 | goto fail; |
| 302 | 328 | ||
| 329 | + s->transfer_len = len; | ||
| 303 | if (scsi_write_data(s->scsi_dev, data, len)) | 330 | if (scsi_write_data(s->scsi_dev, data, len)) |
| 304 | goto fail; | 331 | goto fail; |
| 305 | 332 | ||
| 306 | - s->data_len -= len; | ||
| 307 | - if (s->data_len == 0) | ||
| 308 | - s->mode = USB_MSDM_CSW; | ||
| 309 | - ret = len; | 333 | + if (s->transfer_len == 0) { |
| 334 | + ret = len; | ||
| 335 | + } else { | ||
| 336 | + DPRINTF("Deferring packet %p\n", p); | ||
| 337 | + usb_defer_packet(p, usb_msd_cancel_io, s); | ||
| 338 | + s->packet = p; | ||
| 339 | + ret = USB_RET_ASYNC; | ||
| 340 | + } | ||
| 310 | break; | 341 | break; |
| 311 | 342 | ||
| 312 | default: | 343 | default: |
| @@ -340,13 +371,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, | @@ -340,13 +371,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, | ||
| 340 | if (len > s->data_len) | 371 | if (len > s->data_len) |
| 341 | len = s->data_len; | 372 | len = s->data_len; |
| 342 | 373 | ||
| 374 | + s->transfer_len = len; | ||
| 343 | if (scsi_read_data(s->scsi_dev, data, len)) | 375 | if (scsi_read_data(s->scsi_dev, data, len)) |
| 344 | goto fail; | 376 | goto fail; |
| 345 | 377 | ||
| 346 | - s->data_len -= len; | ||
| 347 | - if (s->data_len == 0) | ||
| 348 | - s->mode = USB_MSDM_CSW; | ||
| 349 | - ret = len; | 378 | + if (s->transfer_len == 0) { |
| 379 | + ret = len; | ||
| 380 | + } else { | ||
| 381 | + DPRINTF("Deferring packet %p\n", p); | ||
| 382 | + usb_defer_packet(p, usb_msd_cancel_io, s); | ||
| 383 | + s->packet = p; | ||
| 384 | + ret = USB_RET_ASYNC; | ||
| 385 | + } | ||
| 350 | break; | 386 | break; |
| 351 | 387 | ||
| 352 | default: | 388 | default: |
hw/usb-ohci.c
| @@ -89,6 +89,14 @@ typedef struct { | @@ -89,6 +89,14 @@ typedef struct { | ||
| 89 | uint32_t rhdesc_a, rhdesc_b; | 89 | uint32_t rhdesc_a, rhdesc_b; |
| 90 | uint32_t rhstatus; | 90 | uint32_t rhstatus; |
| 91 | OHCIPort rhport[OHCI_MAX_PORTS]; | 91 | OHCIPort rhport[OHCI_MAX_PORTS]; |
| 92 | + | ||
| 93 | + /* Active packets. */ | ||
| 94 | + uint32_t old_ctl; | ||
| 95 | + USBPacket usb_packet; | ||
| 96 | + uint8_t usb_buf[8192]; | ||
| 97 | + uint32_t async_td; | ||
| 98 | + int async_complete; | ||
| 99 | + | ||
| 92 | } OHCIState; | 100 | } OHCIState; |
| 93 | 101 | ||
| 94 | /* Host Controller Communications Area */ | 102 | /* Host Controller Communications Area */ |
| @@ -288,8 +296,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | @@ -288,8 +296,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | ||
| 288 | port->ctrl &= ~OHCI_PORT_LSDA; | 296 | port->ctrl &= ~OHCI_PORT_LSDA; |
| 289 | port->port.dev = dev; | 297 | port->port.dev = dev; |
| 290 | /* send the attach message */ | 298 | /* send the attach message */ |
| 291 | - dev->handle_packet(dev, | ||
| 292 | - USB_MSG_ATTACH, 0, 0, NULL, 0); | 299 | + usb_send_msg(dev, USB_MSG_ATTACH); |
| 293 | dprintf("usb-ohci: Attached port %d\n", port1->index); | 300 | dprintf("usb-ohci: Attached port %d\n", port1->index); |
| 294 | } else { | 301 | } else { |
| 295 | /* set connect status */ | 302 | /* set connect status */ |
| @@ -305,8 +312,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | @@ -305,8 +312,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | ||
| 305 | dev = port->port.dev; | 312 | dev = port->port.dev; |
| 306 | if (dev) { | 313 | if (dev) { |
| 307 | /* send the detach message */ | 314 | /* send the detach message */ |
| 308 | - dev->handle_packet(dev, | ||
| 309 | - USB_MSG_DETACH, 0, 0, NULL, 0); | 315 | + usb_send_msg(dev, USB_MSG_DETACH); |
| 310 | } | 316 | } |
| 311 | port->port.dev = NULL; | 317 | port->port.dev = NULL; |
| 312 | dprintf("usb-ohci: Detached port %d\n", port1->index); | 318 | dprintf("usb-ohci: Detached port %d\n", port1->index); |
| @@ -323,6 +329,7 @@ static void ohci_reset(OHCIState *ohci) | @@ -323,6 +329,7 @@ static void ohci_reset(OHCIState *ohci) | ||
| 323 | int i; | 329 | int i; |
| 324 | 330 | ||
| 325 | ohci->ctl = 0; | 331 | ohci->ctl = 0; |
| 332 | + ohci->old_ctl = 0; | ||
| 326 | ohci->status = 0; | 333 | ohci->status = 0; |
| 327 | ohci->intr_status = 0; | 334 | ohci->intr_status = 0; |
| 328 | ohci->intr = OHCI_INTR_MIE; | 335 | ohci->intr = OHCI_INTR_MIE; |
| @@ -356,6 +363,10 @@ static void ohci_reset(OHCIState *ohci) | @@ -356,6 +363,10 @@ static void ohci_reset(OHCIState *ohci) | ||
| 356 | if (port->port.dev) | 363 | if (port->port.dev) |
| 357 | ohci_attach(&port->port, port->port.dev); | 364 | ohci_attach(&port->port, port->port.dev); |
| 358 | } | 365 | } |
| 366 | + if (ohci->async_td) { | ||
| 367 | + usb_cancel_packet(&ohci->usb_packet); | ||
| 368 | + ohci->async_td = 0; | ||
| 369 | + } | ||
| 359 | dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); | 370 | dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); |
| 360 | } | 371 | } |
| 361 | 372 | ||
| @@ -423,6 +434,18 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) | @@ -423,6 +434,18 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) | ||
| 423 | cpu_physical_memory_rw(ptr, buf, len - n, write); | 434 | cpu_physical_memory_rw(ptr, buf, len - n, write); |
| 424 | } | 435 | } |
| 425 | 436 | ||
| 437 | +static void ohci_process_lists(OHCIState *ohci); | ||
| 438 | + | ||
| 439 | +static void ohci_async_complete_packet(USBPacket * packet, void *opaque) | ||
| 440 | +{ | ||
| 441 | + OHCIState *ohci = opaque; | ||
| 442 | +#ifdef DEBUG_PACKET | ||
| 443 | + dprintf("Async packet complete\n"); | ||
| 444 | +#endif | ||
| 445 | + ohci->async_complete = 1; | ||
| 446 | + ohci_process_lists(ohci); | ||
| 447 | +} | ||
| 448 | + | ||
| 426 | /* Service a transport descriptor. | 449 | /* Service a transport descriptor. |
| 427 | Returns nonzero to terminate processing of this endpoint. */ | 450 | Returns nonzero to terminate processing of this endpoint. */ |
| 428 | 451 | ||
| @@ -430,7 +453,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | @@ -430,7 +453,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | ||
| 430 | { | 453 | { |
| 431 | int dir; | 454 | int dir; |
| 432 | size_t len = 0; | 455 | size_t len = 0; |
| 433 | - uint8_t buf[8192]; | ||
| 434 | char *str = NULL; | 456 | char *str = NULL; |
| 435 | int pid; | 457 | int pid; |
| 436 | int ret; | 458 | int ret; |
| @@ -439,8 +461,17 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | @@ -439,8 +461,17 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | ||
| 439 | struct ohci_td td; | 461 | struct ohci_td td; |
| 440 | uint32_t addr; | 462 | uint32_t addr; |
| 441 | int flag_r; | 463 | int flag_r; |
| 464 | + int completion; | ||
| 442 | 465 | ||
| 443 | addr = ed->head & OHCI_DPTR_MASK; | 466 | addr = ed->head & OHCI_DPTR_MASK; |
| 467 | + /* See if this TD has already been submitted to the device. */ | ||
| 468 | + completion = (addr == ohci->async_td); | ||
| 469 | + if (completion && !ohci->async_complete) { | ||
| 470 | +#ifdef DEBUG_PACKET | ||
| 471 | + dprintf("Skipping async TD\n"); | ||
| 472 | +#endif | ||
| 473 | + return 1; | ||
| 474 | + } | ||
| 444 | if (!ohci_read_td(addr, &td)) { | 475 | if (!ohci_read_td(addr, &td)) { |
| 445 | fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); | 476 | fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); |
| 446 | return 0; | 477 | return 0; |
| @@ -481,8 +512,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | @@ -481,8 +512,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | ||
| 481 | len = (td.be - td.cbp) + 1; | 512 | len = (td.be - td.cbp) + 1; |
| 482 | } | 513 | } |
| 483 | 514 | ||
| 484 | - if (len && dir != OHCI_TD_DIR_IN) { | ||
| 485 | - ohci_copy_td(&td, buf, len, 0); | 515 | + if (len && dir != OHCI_TD_DIR_IN && !completion) { |
| 516 | + ohci_copy_td(&td, ohci->usb_buf, len, 0); | ||
| 486 | } | 517 | } |
| 487 | } | 518 | } |
| 488 | 519 | ||
| @@ -494,31 +525,58 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | @@ -494,31 +525,58 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | ||
| 494 | if (len >= 0 && dir != OHCI_TD_DIR_IN) { | 525 | if (len >= 0 && dir != OHCI_TD_DIR_IN) { |
| 495 | dprintf(" data:"); | 526 | dprintf(" data:"); |
| 496 | for (i = 0; i < len; i++) | 527 | for (i = 0; i < len; i++) |
| 497 | - printf(" %.2x", buf[i]); | 528 | + printf(" %.2x", ohci->usb_buf[i]); |
| 498 | dprintf("\n"); | 529 | dprintf("\n"); |
| 499 | } | 530 | } |
| 500 | #endif | 531 | #endif |
| 501 | - ret = USB_RET_NODEV; | ||
| 502 | - for (i = 0; i < ohci->num_ports; i++) { | ||
| 503 | - dev = ohci->rhport[i].port.dev; | ||
| 504 | - if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) | ||
| 505 | - continue; | ||
| 506 | - | ||
| 507 | - ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), | ||
| 508 | - OHCI_BM(ed->flags, ED_EN), buf, len); | ||
| 509 | - if (ret != USB_RET_NODEV) | ||
| 510 | - break; | ||
| 511 | - } | 532 | + if (completion) { |
| 533 | + ret = ohci->usb_packet.len; | ||
| 534 | + ohci->async_td = 0; | ||
| 535 | + ohci->async_complete = 0; | ||
| 536 | + } else { | ||
| 537 | + ret = USB_RET_NODEV; | ||
| 538 | + for (i = 0; i < ohci->num_ports; i++) { | ||
| 539 | + dev = ohci->rhport[i].port.dev; | ||
| 540 | + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) | ||
| 541 | + continue; | ||
| 542 | + | ||
| 543 | + if (ohci->async_td) { | ||
| 544 | + /* ??? The hardware should allow one active packet per | ||
| 545 | + endpoint. We only allow one active packet per controller. | ||
| 546 | + This should be sufficient as long as devices respond in a | ||
| 547 | + timely manner. | ||
| 548 | + */ | ||
| 512 | #ifdef DEBUG_PACKET | 549 | #ifdef DEBUG_PACKET |
| 513 | - dprintf("ret=%d\n", ret); | 550 | + dprintf("Too many pending packets\n"); |
| 514 | #endif | 551 | #endif |
| 552 | + return 1; | ||
| 553 | + } | ||
| 554 | + ohci->usb_packet.pid = pid; | ||
| 555 | + ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA); | ||
| 556 | + ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN); | ||
| 557 | + ohci->usb_packet.data = ohci->usb_buf; | ||
| 558 | + ohci->usb_packet.len = len; | ||
| 559 | + ohci->usb_packet.complete_cb = ohci_async_complete_packet; | ||
| 560 | + ohci->usb_packet.complete_opaque = ohci; | ||
| 561 | + ret = dev->handle_packet(dev, &ohci->usb_packet); | ||
| 562 | + if (ret != USB_RET_NODEV) | ||
| 563 | + break; | ||
| 564 | + } | ||
| 565 | +#ifdef DEBUG_PACKET | ||
| 566 | + dprintf("ret=%d\n", ret); | ||
| 567 | +#endif | ||
| 568 | + if (ret == USB_RET_ASYNC) { | ||
| 569 | + ohci->async_td = addr; | ||
| 570 | + return 1; | ||
| 571 | + } | ||
| 572 | + } | ||
| 515 | if (ret >= 0) { | 573 | if (ret >= 0) { |
| 516 | if (dir == OHCI_TD_DIR_IN) { | 574 | if (dir == OHCI_TD_DIR_IN) { |
| 517 | - ohci_copy_td(&td, buf, ret, 1); | 575 | + ohci_copy_td(&td, ohci->usb_buf, ret, 1); |
| 518 | #ifdef DEBUG_PACKET | 576 | #ifdef DEBUG_PACKET |
| 519 | dprintf(" data:"); | 577 | dprintf(" data:"); |
| 520 | for (i = 0; i < ret; i++) | 578 | for (i = 0; i < ret; i++) |
| 521 | - printf(" %.2x", buf[i]); | 579 | + printf(" %.2x", ohci->usb_buf[i]); |
| 522 | dprintf("\n"); | 580 | dprintf("\n"); |
| 523 | #endif | 581 | #endif |
| 524 | } else { | 582 | } else { |
| @@ -608,8 +666,16 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) | @@ -608,8 +666,16 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) | ||
| 608 | 666 | ||
| 609 | next_ed = ed.next & OHCI_DPTR_MASK; | 667 | next_ed = ed.next & OHCI_DPTR_MASK; |
| 610 | 668 | ||
| 611 | - if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) | 669 | + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { |
| 670 | + uint32_t addr; | ||
| 671 | + /* Cancel pending packets for ED that have been paused. */ | ||
| 672 | + addr = ed.head & OHCI_DPTR_MASK; | ||
| 673 | + if (ohci->async_td && addr == ohci->async_td) { | ||
| 674 | + usb_cancel_packet(&ohci->usb_packet); | ||
| 675 | + ohci->async_td = 0; | ||
| 676 | + } | ||
| 612 | continue; | 677 | continue; |
| 678 | + } | ||
| 613 | 679 | ||
| 614 | /* Skip isochronous endpoints. */ | 680 | /* Skip isochronous endpoints. */ |
| 615 | if (ed.flags & OHCI_ED_F) | 681 | if (ed.flags & OHCI_ED_F) |
| @@ -646,6 +712,26 @@ static void ohci_sof(OHCIState *ohci) | @@ -646,6 +712,26 @@ static void ohci_sof(OHCIState *ohci) | ||
| 646 | ohci_set_interrupt(ohci, OHCI_INTR_SF); | 712 | ohci_set_interrupt(ohci, OHCI_INTR_SF); |
| 647 | } | 713 | } |
| 648 | 714 | ||
| 715 | +/* Process Control and Bulk lists. */ | ||
| 716 | +static void ohci_process_lists(OHCIState *ohci) | ||
| 717 | +{ | ||
| 718 | + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { | ||
| 719 | + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) | ||
| 720 | + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); | ||
| 721 | + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { | ||
| 722 | + ohci->ctrl_cur = 0; | ||
| 723 | + ohci->status &= ~OHCI_STATUS_CLF; | ||
| 724 | + } | ||
| 725 | + } | ||
| 726 | + | ||
| 727 | + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { | ||
| 728 | + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { | ||
| 729 | + ohci->bulk_cur = 0; | ||
| 730 | + ohci->status &= ~OHCI_STATUS_BLF; | ||
| 731 | + } | ||
| 732 | + } | ||
| 733 | +} | ||
| 734 | + | ||
| 649 | /* Do frame processing on frame boundary */ | 735 | /* Do frame processing on frame boundary */ |
| 650 | static void ohci_frame_boundary(void *opaque) | 736 | static void ohci_frame_boundary(void *opaque) |
| 651 | { | 737 | { |
| @@ -661,21 +747,15 @@ static void ohci_frame_boundary(void *opaque) | @@ -661,21 +747,15 @@ static void ohci_frame_boundary(void *opaque) | ||
| 661 | n = ohci->frame_number & 0x1f; | 747 | n = ohci->frame_number & 0x1f; |
| 662 | ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); | 748 | ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); |
| 663 | } | 749 | } |
| 664 | - if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { | ||
| 665 | - if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) | ||
| 666 | - dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); | ||
| 667 | - if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { | ||
| 668 | - ohci->ctrl_cur = 0; | ||
| 669 | - ohci->status &= ~OHCI_STATUS_CLF; | ||
| 670 | - } | ||
| 671 | - } | ||
| 672 | 750 | ||
| 673 | - if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { | ||
| 674 | - if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { | ||
| 675 | - ohci->bulk_cur = 0; | ||
| 676 | - ohci->status &= ~OHCI_STATUS_BLF; | ||
| 677 | - } | 751 | + /* Cancel all pending packets if either of the lists has been disabled. */ |
| 752 | + if (ohci->async_td && | ||
| 753 | + ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { | ||
| 754 | + usb_cancel_packet(&ohci->usb_packet); | ||
| 755 | + ohci->async_td = 0; | ||
| 678 | } | 756 | } |
| 757 | + ohci->old_ctl = ohci->ctl; | ||
| 758 | + ohci_process_lists(ohci); | ||
| 679 | 759 | ||
| 680 | /* Frame boundary, so do EOF stuf here */ | 760 | /* Frame boundary, so do EOF stuf here */ |
| 681 | ohci->frt = ohci->fit; | 761 | ohci->frt = ohci->fit; |
| @@ -907,8 +987,7 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) | @@ -907,8 +987,7 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) | ||
| 907 | 987 | ||
| 908 | if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { | 988 | if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { |
| 909 | dprintf("usb-ohci: port %d: RESET\n", portnum); | 989 | dprintf("usb-ohci: port %d: RESET\n", portnum); |
| 910 | - port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, | ||
| 911 | - 0, 0, NULL, 0); | 990 | + usb_send_msg(port->port.dev, USB_MSG_RESET); |
| 912 | port->ctrl &= ~OHCI_PORT_PRS; | 991 | port->ctrl &= ~OHCI_PORT_PRS; |
| 913 | /* ??? Should this also set OHCI_PORT_PESC. */ | 992 | /* ??? Should this also set OHCI_PORT_PESC. */ |
| 914 | port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; | 993 | port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; |
| @@ -1186,5 +1265,6 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) | @@ -1186,5 +1265,6 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) | ||
| 1186 | qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); | 1265 | qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); |
| 1187 | } | 1266 | } |
| 1188 | 1267 | ||
| 1268 | + ohci->async_td = 0; | ||
| 1189 | ohci_reset(ohci); | 1269 | ohci_reset(ohci); |
| 1190 | } | 1270 | } |
hw/usb-uhci.c
| @@ -76,6 +76,18 @@ typedef struct UHCIState { | @@ -76,6 +76,18 @@ typedef struct UHCIState { | ||
| 76 | uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ | 76 | uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ |
| 77 | QEMUTimer *frame_timer; | 77 | QEMUTimer *frame_timer; |
| 78 | UHCIPort ports[NB_PORTS]; | 78 | UHCIPort ports[NB_PORTS]; |
| 79 | + | ||
| 80 | + /* Interrupts that should be raised at the end of the current frame. */ | ||
| 81 | + uint32_t pending_int_mask; | ||
| 82 | + /* For simplicity of implementation we only allow a single pending USB | ||
| 83 | + request. This means all usb traffic on this controller is effectively | ||
| 84 | + suspended until that transfer completes. When the transfer completes | ||
| 85 | + the next transfer from that queue will be processed. However | ||
| 86 | + other queues will not be processed until the next frame. The solution | ||
| 87 | + is to allow multiple pending requests. */ | ||
| 88 | + uint32_t async_qh; | ||
| 89 | + USBPacket usb_packet; | ||
| 90 | + uint8_t usb_buf[1280]; | ||
| 79 | } UHCIState; | 91 | } UHCIState; |
| 80 | 92 | ||
| 81 | typedef struct UHCI_TD { | 93 | typedef struct UHCI_TD { |
| @@ -188,8 +200,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | @@ -188,8 +200,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | ||
| 188 | port = &s->ports[i]; | 200 | port = &s->ports[i]; |
| 189 | dev = port->port.dev; | 201 | dev = port->port.dev; |
| 190 | if (dev) { | 202 | if (dev) { |
| 191 | - dev->handle_packet(dev, | ||
| 192 | - USB_MSG_RESET, 0, 0, NULL, 0); | 203 | + usb_send_msg(dev, USB_MSG_RESET); |
| 193 | } | 204 | } |
| 194 | } | 205 | } |
| 195 | uhci_reset(s); | 206 | uhci_reset(s); |
| @@ -232,8 +243,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | @@ -232,8 +243,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | ||
| 232 | /* port reset */ | 243 | /* port reset */ |
| 233 | if ( (val & UHCI_PORT_RESET) && | 244 | if ( (val & UHCI_PORT_RESET) && |
| 234 | !(port->ctrl & UHCI_PORT_RESET) ) { | 245 | !(port->ctrl & UHCI_PORT_RESET) ) { |
| 235 | - dev->handle_packet(dev, | ||
| 236 | - USB_MSG_RESET, 0, 0, NULL, 0); | 246 | + usb_send_msg(dev, USB_MSG_RESET); |
| 237 | } | 247 | } |
| 238 | } | 248 | } |
| 239 | port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); | 249 | port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); |
| @@ -336,8 +346,7 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | @@ -336,8 +346,7 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | ||
| 336 | port->ctrl &= ~UHCI_PORT_LSDA; | 346 | port->ctrl &= ~UHCI_PORT_LSDA; |
| 337 | port->port.dev = dev; | 347 | port->port.dev = dev; |
| 338 | /* send the attach message */ | 348 | /* send the attach message */ |
| 339 | - dev->handle_packet(dev, | ||
| 340 | - USB_MSG_ATTACH, 0, 0, NULL, 0); | 349 | + usb_send_msg(dev, USB_MSG_ATTACH); |
| 341 | } else { | 350 | } else { |
| 342 | /* set connect status */ | 351 | /* set connect status */ |
| 343 | if (port->ctrl & UHCI_PORT_CCS) { | 352 | if (port->ctrl & UHCI_PORT_CCS) { |
| @@ -352,16 +361,13 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | @@ -352,16 +361,13 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | ||
| 352 | dev = port->port.dev; | 361 | dev = port->port.dev; |
| 353 | if (dev) { | 362 | if (dev) { |
| 354 | /* send the detach message */ | 363 | /* send the detach message */ |
| 355 | - dev->handle_packet(dev, | ||
| 356 | - USB_MSG_DETACH, 0, 0, NULL, 0); | 364 | + usb_send_msg(dev, USB_MSG_DETACH); |
| 357 | } | 365 | } |
| 358 | port->port.dev = NULL; | 366 | port->port.dev = NULL; |
| 359 | } | 367 | } |
| 360 | } | 368 | } |
| 361 | 369 | ||
| 362 | -static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | ||
| 363 | - uint8_t devaddr, uint8_t devep, | ||
| 364 | - uint8_t *data, int len) | 370 | +static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) |
| 365 | { | 371 | { |
| 366 | UHCIPort *port; | 372 | UHCIPort *port; |
| 367 | USBDevice *dev; | 373 | USBDevice *dev; |
| @@ -370,18 +376,18 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | @@ -370,18 +376,18 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | ||
| 370 | #ifdef DEBUG_PACKET | 376 | #ifdef DEBUG_PACKET |
| 371 | { | 377 | { |
| 372 | const char *pidstr; | 378 | const char *pidstr; |
| 373 | - switch(pid) { | 379 | + switch(p->pid) { |
| 374 | case USB_TOKEN_SETUP: pidstr = "SETUP"; break; | 380 | case USB_TOKEN_SETUP: pidstr = "SETUP"; break; |
| 375 | case USB_TOKEN_IN: pidstr = "IN"; break; | 381 | case USB_TOKEN_IN: pidstr = "IN"; break; |
| 376 | case USB_TOKEN_OUT: pidstr = "OUT"; break; | 382 | case USB_TOKEN_OUT: pidstr = "OUT"; break; |
| 377 | default: pidstr = "?"; break; | 383 | default: pidstr = "?"; break; |
| 378 | } | 384 | } |
| 379 | printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", | 385 | printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", |
| 380 | - s->frnum, pidstr, devaddr, devep, len); | ||
| 381 | - if (pid != USB_TOKEN_IN) { | 386 | + s->frnum, pidstr, p->devaddr, p->devep, p->len); |
| 387 | + if (p->pid != USB_TOKEN_IN) { | ||
| 382 | printf(" data_out="); | 388 | printf(" data_out="); |
| 383 | - for(i = 0; i < len; i++) { | ||
| 384 | - printf(" %02x", data[i]); | 389 | + for(i = 0; i < p->len; i++) { |
| 390 | + printf(" %02x", p->data[i]); | ||
| 385 | } | 391 | } |
| 386 | printf("\n"); | 392 | printf("\n"); |
| 387 | } | 393 | } |
| @@ -391,17 +397,17 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | @@ -391,17 +397,17 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | ||
| 391 | port = &s->ports[i]; | 397 | port = &s->ports[i]; |
| 392 | dev = port->port.dev; | 398 | dev = port->port.dev; |
| 393 | if (dev && (port->ctrl & UHCI_PORT_EN)) { | 399 | if (dev && (port->ctrl & UHCI_PORT_EN)) { |
| 394 | - ret = dev->handle_packet(dev, pid, | ||
| 395 | - devaddr, devep, | ||
| 396 | - data, len); | 400 | + ret = dev->handle_packet(dev, p); |
| 397 | if (ret != USB_RET_NODEV) { | 401 | if (ret != USB_RET_NODEV) { |
| 398 | #ifdef DEBUG_PACKET | 402 | #ifdef DEBUG_PACKET |
| 399 | - { | 403 | + if (ret == USB_RET_ASYNC) { |
| 404 | + printf("usb-uhci: Async packet\n"); | ||
| 405 | + } else { | ||
| 400 | printf(" ret=%d ", ret); | 406 | printf(" ret=%d ", ret); |
| 401 | - if (pid == USB_TOKEN_IN && ret > 0) { | 407 | + if (p->pid == USB_TOKEN_IN && ret > 0) { |
| 402 | printf("data_in="); | 408 | printf("data_in="); |
| 403 | for(i = 0; i < ret; i++) { | 409 | for(i = 0; i < ret; i++) { |
| 404 | - printf(" %02x", data[i]); | 410 | + printf(" %02x", p->data[i]); |
| 405 | } | 411 | } |
| 406 | } | 412 | } |
| 407 | printf("\n"); | 413 | printf("\n"); |
| @@ -414,6 +420,8 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | @@ -414,6 +420,8 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | ||
| 414 | return USB_RET_NODEV; | 420 | return USB_RET_NODEV; |
| 415 | } | 421 | } |
| 416 | 422 | ||
| 423 | +static void uhci_async_complete_packet(USBPacket * packet, void *opaque); | ||
| 424 | + | ||
| 417 | /* return -1 if fatal error (frame must be stopped) | 425 | /* return -1 if fatal error (frame must be stopped) |
| 418 | 0 if TD successful | 426 | 0 if TD successful |
| 419 | 1 if TD unsuccessful or inactive | 427 | 1 if TD unsuccessful or inactive |
| @@ -421,9 +429,9 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | @@ -421,9 +429,9 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, | ||
| 421 | static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | 429 | static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) |
| 422 | { | 430 | { |
| 423 | uint8_t pid; | 431 | uint8_t pid; |
| 424 | - uint8_t buf[1280]; | ||
| 425 | int len, max_len, err, ret; | 432 | int len, max_len, err, ret; |
| 426 | 433 | ||
| 434 | + /* ??? This is wrong for async completion. */ | ||
| 427 | if (td->ctrl & TD_CTRL_IOC) { | 435 | if (td->ctrl & TD_CTRL_IOC) { |
| 428 | *int_mask |= 0x01; | 436 | *int_mask |= 0x01; |
| 429 | } | 437 | } |
| @@ -434,21 +442,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | @@ -434,21 +442,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | ||
| 434 | /* TD is active */ | 442 | /* TD is active */ |
| 435 | max_len = ((td->token >> 21) + 1) & 0x7ff; | 443 | max_len = ((td->token >> 21) + 1) & 0x7ff; |
| 436 | pid = td->token & 0xff; | 444 | pid = td->token & 0xff; |
| 437 | - switch(pid) { | ||
| 438 | - case USB_TOKEN_OUT: | ||
| 439 | - case USB_TOKEN_SETUP: | ||
| 440 | - cpu_physical_memory_read(td->buffer, buf, max_len); | ||
| 441 | - ret = uhci_broadcast_packet(s, pid, | ||
| 442 | - (td->token >> 8) & 0x7f, | ||
| 443 | - (td->token >> 15) & 0xf, | ||
| 444 | - buf, max_len); | ||
| 445 | - len = max_len; | ||
| 446 | - break; | ||
| 447 | - case USB_TOKEN_IN: | ||
| 448 | - ret = uhci_broadcast_packet(s, pid, | ||
| 449 | - (td->token >> 8) & 0x7f, | ||
| 450 | - (td->token >> 15) & 0xf, | ||
| 451 | - buf, max_len); | 445 | + if (s->async_qh) { |
| 446 | + ret = s->usb_packet.len; | ||
| 452 | if (ret >= 0) { | 447 | if (ret >= 0) { |
| 453 | len = ret; | 448 | len = ret; |
| 454 | if (len > max_len) { | 449 | if (len > max_len) { |
| @@ -457,17 +452,52 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | @@ -457,17 +452,52 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | ||
| 457 | } | 452 | } |
| 458 | if (len > 0) { | 453 | if (len > 0) { |
| 459 | /* write the data back */ | 454 | /* write the data back */ |
| 460 | - cpu_physical_memory_write(td->buffer, buf, len); | 455 | + cpu_physical_memory_write(td->buffer, s->usb_buf, len); |
| 461 | } | 456 | } |
| 462 | } else { | 457 | } else { |
| 463 | len = 0; | 458 | len = 0; |
| 464 | } | 459 | } |
| 465 | - break; | ||
| 466 | - default: | ||
| 467 | - /* invalid pid : frame interrupted */ | ||
| 468 | - s->status |= UHCI_STS_HCPERR; | ||
| 469 | - uhci_update_irq(s); | ||
| 470 | - return -1; | 460 | + s->async_qh = 0; |
| 461 | + } else { | ||
| 462 | + s->usb_packet.pid = pid; | ||
| 463 | + s->usb_packet.devaddr = (td->token >> 8) & 0x7f; | ||
| 464 | + s->usb_packet.devep = (td->token >> 15) & 0xf; | ||
| 465 | + s->usb_packet.data = s->usb_buf; | ||
| 466 | + s->usb_packet.len = max_len; | ||
| 467 | + s->usb_packet.complete_cb = uhci_async_complete_packet; | ||
| 468 | + s->usb_packet.complete_opaque = s; | ||
| 469 | + switch(pid) { | ||
| 470 | + case USB_TOKEN_OUT: | ||
| 471 | + case USB_TOKEN_SETUP: | ||
| 472 | + cpu_physical_memory_read(td->buffer, s->usb_buf, max_len); | ||
| 473 | + ret = uhci_broadcast_packet(s, &s->usb_packet); | ||
| 474 | + len = max_len; | ||
| 475 | + break; | ||
| 476 | + case USB_TOKEN_IN: | ||
| 477 | + ret = uhci_broadcast_packet(s, &s->usb_packet); | ||
| 478 | + if (ret >= 0) { | ||
| 479 | + len = ret; | ||
| 480 | + if (len > max_len) { | ||
| 481 | + len = max_len; | ||
| 482 | + ret = USB_RET_BABBLE; | ||
| 483 | + } | ||
| 484 | + if (len > 0) { | ||
| 485 | + /* write the data back */ | ||
| 486 | + cpu_physical_memory_write(td->buffer, s->usb_buf, len); | ||
| 487 | + } | ||
| 488 | + } else { | ||
| 489 | + len = 0; | ||
| 490 | + } | ||
| 491 | + break; | ||
| 492 | + default: | ||
| 493 | + /* invalid pid : frame interrupted */ | ||
| 494 | + s->status |= UHCI_STS_HCPERR; | ||
| 495 | + uhci_update_irq(s); | ||
| 496 | + return -1; | ||
| 497 | + } | ||
| 498 | + } | ||
| 499 | + if (ret == USB_RET_ASYNC) { | ||
| 500 | + return 2; | ||
| 471 | } | 501 | } |
| 472 | if (td->ctrl & TD_CTRL_IOS) | 502 | if (td->ctrl & TD_CTRL_IOS) |
| 473 | td->ctrl &= ~TD_CTRL_ACTIVE; | 503 | td->ctrl &= ~TD_CTRL_ACTIVE; |
| @@ -520,6 +550,61 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | @@ -520,6 +550,61 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | ||
| 520 | } | 550 | } |
| 521 | } | 551 | } |
| 522 | 552 | ||
| 553 | +static void uhci_async_complete_packet(USBPacket * packet, void *opaque) | ||
| 554 | +{ | ||
| 555 | + UHCIState *s = opaque; | ||
| 556 | + UHCI_QH qh; | ||
| 557 | + UHCI_TD td; | ||
| 558 | + uint32_t link; | ||
| 559 | + uint32_t old_td_ctrl; | ||
| 560 | + uint32_t val; | ||
| 561 | + int ret; | ||
| 562 | + | ||
| 563 | + link = s->async_qh; | ||
| 564 | + if (!link) { | ||
| 565 | + /* This should never happen. It means a TD somehow got removed | ||
| 566 | + without cancelling the associated async IO request. */ | ||
| 567 | + return; | ||
| 568 | + } | ||
| 569 | + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); | ||
| 570 | + le32_to_cpus(&qh.link); | ||
| 571 | + le32_to_cpus(&qh.el_link); | ||
| 572 | + /* Re-process the queue containing the async packet. */ | ||
| 573 | + while (1) { | ||
| 574 | + cpu_physical_memory_read(qh.el_link & ~0xf, | ||
| 575 | + (uint8_t *)&td, sizeof(td)); | ||
| 576 | + le32_to_cpus(&td.link); | ||
| 577 | + le32_to_cpus(&td.ctrl); | ||
| 578 | + le32_to_cpus(&td.token); | ||
| 579 | + le32_to_cpus(&td.buffer); | ||
| 580 | + old_td_ctrl = td.ctrl; | ||
| 581 | + ret = uhci_handle_td(s, &td, &s->pending_int_mask); | ||
| 582 | + /* update the status bits of the TD */ | ||
| 583 | + if (old_td_ctrl != td.ctrl) { | ||
| 584 | + val = cpu_to_le32(td.ctrl); | ||
| 585 | + cpu_physical_memory_write((qh.el_link & ~0xf) + 4, | ||
| 586 | + (const uint8_t *)&val, | ||
| 587 | + sizeof(val)); | ||
| 588 | + } | ||
| 589 | + if (ret < 0) | ||
| 590 | + break; /* interrupted frame */ | ||
| 591 | + if (ret == 2) { | ||
| 592 | + s->async_qh = link; | ||
| 593 | + break; | ||
| 594 | + } else if (ret == 0) { | ||
| 595 | + /* update qh element link */ | ||
| 596 | + qh.el_link = td.link; | ||
| 597 | + val = cpu_to_le32(qh.el_link); | ||
| 598 | + cpu_physical_memory_write((link & ~0xf) + 4, | ||
| 599 | + (const uint8_t *)&val, | ||
| 600 | + sizeof(val)); | ||
| 601 | + if (!(qh.el_link & 4)) | ||
| 602 | + break; | ||
| 603 | + } | ||
| 604 | + break; | ||
| 605 | + } | ||
| 606 | +} | ||
| 607 | + | ||
| 523 | static void uhci_frame_timer(void *opaque) | 608 | static void uhci_frame_timer(void *opaque) |
| 524 | { | 609 | { |
| 525 | UHCIState *s = opaque; | 610 | UHCIState *s = opaque; |
| @@ -528,6 +613,7 @@ static void uhci_frame_timer(void *opaque) | @@ -528,6 +613,7 @@ static void uhci_frame_timer(void *opaque) | ||
| 528 | int int_mask, cnt, ret; | 613 | int int_mask, cnt, ret; |
| 529 | UHCI_TD td; | 614 | UHCI_TD td; |
| 530 | UHCI_QH qh; | 615 | UHCI_QH qh; |
| 616 | + uint32_t old_async_qh; | ||
| 531 | 617 | ||
| 532 | if (!(s->cmd & UHCI_CMD_RS)) { | 618 | if (!(s->cmd & UHCI_CMD_RS)) { |
| 533 | qemu_del_timer(s->frame_timer); | 619 | qemu_del_timer(s->frame_timer); |
| @@ -535,6 +621,14 @@ static void uhci_frame_timer(void *opaque) | @@ -535,6 +621,14 @@ static void uhci_frame_timer(void *opaque) | ||
| 535 | s->status |= UHCI_STS_HCHALTED; | 621 | s->status |= UHCI_STS_HCHALTED; |
| 536 | return; | 622 | return; |
| 537 | } | 623 | } |
| 624 | + /* Complete the previous frame. */ | ||
| 625 | + s->frnum = (s->frnum + 1) & 0x7ff; | ||
| 626 | + if (s->pending_int_mask) { | ||
| 627 | + s->status2 |= s->pending_int_mask; | ||
| 628 | + s->status |= UHCI_STS_USBINT; | ||
| 629 | + uhci_update_irq(s); | ||
| 630 | + } | ||
| 631 | + old_async_qh = s->async_qh; | ||
| 538 | frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); | 632 | frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); |
| 539 | cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); | 633 | cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); |
| 540 | le32_to_cpus(&link); | 634 | le32_to_cpus(&link); |
| @@ -546,6 +640,12 @@ static void uhci_frame_timer(void *opaque) | @@ -546,6 +640,12 @@ static void uhci_frame_timer(void *opaque) | ||
| 546 | /* valid frame */ | 640 | /* valid frame */ |
| 547 | if (link & 2) { | 641 | if (link & 2) { |
| 548 | /* QH */ | 642 | /* QH */ |
| 643 | + if (link == s->async_qh) { | ||
| 644 | + /* We've found a previously issues packet. | ||
| 645 | + Nothing else to do. */ | ||
| 646 | + old_async_qh = 0; | ||
| 647 | + break; | ||
| 648 | + } | ||
| 549 | cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); | 649 | cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); |
| 550 | le32_to_cpus(&qh.link); | 650 | le32_to_cpus(&qh.link); |
| 551 | le32_to_cpus(&qh.el_link); | 651 | le32_to_cpus(&qh.el_link); |
| @@ -556,6 +656,10 @@ static void uhci_frame_timer(void *opaque) | @@ -556,6 +656,10 @@ static void uhci_frame_timer(void *opaque) | ||
| 556 | } else if (qh.el_link & 2) { | 656 | } else if (qh.el_link & 2) { |
| 557 | /* QH */ | 657 | /* QH */ |
| 558 | link = qh.el_link; | 658 | link = qh.el_link; |
| 659 | + } else if (s->async_qh) { | ||
| 660 | + /* We can only cope with one pending packet. Keep looking | ||
| 661 | + for the previously issued packet. */ | ||
| 662 | + link = qh.link; | ||
| 559 | } else { | 663 | } else { |
| 560 | /* TD */ | 664 | /* TD */ |
| 561 | if (--cnt == 0) | 665 | if (--cnt == 0) |
| @@ -577,7 +681,9 @@ static void uhci_frame_timer(void *opaque) | @@ -577,7 +681,9 @@ static void uhci_frame_timer(void *opaque) | ||
| 577 | } | 681 | } |
| 578 | if (ret < 0) | 682 | if (ret < 0) |
| 579 | break; /* interrupted frame */ | 683 | break; /* interrupted frame */ |
| 580 | - if (ret == 0) { | 684 | + if (ret == 2) { |
| 685 | + s->async_qh = link; | ||
| 686 | + } else if (ret == 0) { | ||
| 581 | /* update qh element link */ | 687 | /* update qh element link */ |
| 582 | qh.el_link = td.link; | 688 | qh.el_link = td.link; |
| 583 | val = cpu_to_le32(qh.el_link); | 689 | val = cpu_to_le32(qh.el_link); |
| @@ -599,25 +705,41 @@ static void uhci_frame_timer(void *opaque) | @@ -599,25 +705,41 @@ static void uhci_frame_timer(void *opaque) | ||
| 599 | le32_to_cpus(&td.ctrl); | 705 | le32_to_cpus(&td.ctrl); |
| 600 | le32_to_cpus(&td.token); | 706 | le32_to_cpus(&td.token); |
| 601 | le32_to_cpus(&td.buffer); | 707 | le32_to_cpus(&td.buffer); |
| 602 | - old_td_ctrl = td.ctrl; | ||
| 603 | - ret = uhci_handle_td(s, &td, &int_mask); | ||
| 604 | - /* update the status bits of the TD */ | ||
| 605 | - if (old_td_ctrl != td.ctrl) { | ||
| 606 | - val = cpu_to_le32(td.ctrl); | ||
| 607 | - cpu_physical_memory_write((link & ~0xf) + 4, | ||
| 608 | - (const uint8_t *)&val, | ||
| 609 | - sizeof(val)); | 708 | + /* Ignore isochonous transfers while there is an async packet |
| 709 | + pending. This is wrong, but we don't implement isochronous | ||
| 710 | + transfers anyway. */ | ||
| 711 | + if (s->async_qh == 0) { | ||
| 712 | + old_td_ctrl = td.ctrl; | ||
| 713 | + ret = uhci_handle_td(s, &td, &int_mask); | ||
| 714 | + /* update the status bits of the TD */ | ||
| 715 | + if (old_td_ctrl != td.ctrl) { | ||
| 716 | + val = cpu_to_le32(td.ctrl); | ||
| 717 | + cpu_physical_memory_write((link & ~0xf) + 4, | ||
| 718 | + (const uint8_t *)&val, | ||
| 719 | + sizeof(val)); | ||
| 720 | + } | ||
| 721 | + if (ret < 0) | ||
| 722 | + break; /* interrupted frame */ | ||
| 723 | + if (ret == 2) { | ||
| 724 | + /* We can't handle async isochronous transfers. | ||
| 725 | + Cancel The packet. */ | ||
| 726 | + fprintf(stderr, "usb-uhci: Unimplemented async packet\n"); | ||
| 727 | + usb_cancel_packet(&s->usb_packet); | ||
| 728 | + } | ||
| 610 | } | 729 | } |
| 611 | - if (ret < 0) | ||
| 612 | - break; /* interrupted frame */ | ||
| 613 | link = td.link; | 730 | link = td.link; |
| 614 | } | 731 | } |
| 615 | } | 732 | } |
| 616 | - s->frnum = (s->frnum + 1) & 0x7ff; | ||
| 617 | - if (int_mask) { | ||
| 618 | - s->status2 |= int_mask; | ||
| 619 | - s->status |= UHCI_STS_USBINT; | ||
| 620 | - uhci_update_irq(s); | 733 | + s->pending_int_mask = int_mask; |
| 734 | + if (old_async_qh) { | ||
| 735 | + /* A previously started transfer has disappeared from the transfer | ||
| 736 | + list. There's nothing useful we can do with it now, so just | ||
| 737 | + discard the packet and hope it wasn't too important. */ | ||
| 738 | +#ifdef DEBUG | ||
| 739 | + printf("Discarding USB packet\n"); | ||
| 740 | +#endif | ||
| 741 | + usb_cancel_packet(&s->usb_packet); | ||
| 742 | + s->async_qh = 0; | ||
| 621 | } | 743 | } |
| 622 | /* prepare the timer for the next frame */ | 744 | /* prepare the timer for the next frame */ |
| 623 | expire_time = qemu_get_clock(vm_clock) + | 745 | expire_time = qemu_get_clock(vm_clock) + |
hw/usb.c
| @@ -38,13 +38,13 @@ void usb_attach(USBPort *port, USBDevice *dev) | @@ -38,13 +38,13 @@ void usb_attach(USBPort *port, USBDevice *dev) | ||
| 38 | #define SETUP_STATE_DATA 1 | 38 | #define SETUP_STATE_DATA 1 |
| 39 | #define SETUP_STATE_ACK 2 | 39 | #define SETUP_STATE_ACK 2 |
| 40 | 40 | ||
| 41 | -int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 42 | - uint8_t devaddr, uint8_t devep, | ||
| 43 | - uint8_t *data, int len) | 41 | +int usb_generic_handle_packet(USBDevice *s, USBPacket *p) |
| 44 | { | 42 | { |
| 45 | int l, ret = 0; | 43 | int l, ret = 0; |
| 44 | + int len = p->len; | ||
| 45 | + uint8_t *data = p->data; | ||
| 46 | 46 | ||
| 47 | - switch(pid) { | 47 | + switch(p->pid) { |
| 48 | case USB_MSG_ATTACH: | 48 | case USB_MSG_ATTACH: |
| 49 | s->state = USB_STATE_ATTACHED; | 49 | s->state = USB_STATE_ATTACHED; |
| 50 | break; | 50 | break; |
| @@ -58,7 +58,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | @@ -58,7 +58,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 58 | s->handle_reset(s); | 58 | s->handle_reset(s); |
| 59 | break; | 59 | break; |
| 60 | case USB_TOKEN_SETUP: | 60 | case USB_TOKEN_SETUP: |
| 61 | - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) | 61 | + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) |
| 62 | return USB_RET_NODEV; | 62 | return USB_RET_NODEV; |
| 63 | if (len != 8) | 63 | if (len != 8) |
| 64 | goto fail; | 64 | goto fail; |
| @@ -85,9 +85,9 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | @@ -85,9 +85,9 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 85 | } | 85 | } |
| 86 | break; | 86 | break; |
| 87 | case USB_TOKEN_IN: | 87 | case USB_TOKEN_IN: |
| 88 | - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) | 88 | + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) |
| 89 | return USB_RET_NODEV; | 89 | return USB_RET_NODEV; |
| 90 | - switch(devep) { | 90 | + switch(p->devep) { |
| 91 | case 0: | 91 | case 0: |
| 92 | switch(s->setup_state) { | 92 | switch(s->setup_state) { |
| 93 | case SETUP_STATE_ACK: | 93 | case SETUP_STATE_ACK: |
| @@ -125,14 +125,14 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | @@ -125,14 +125,14 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 125 | } | 125 | } |
| 126 | break; | 126 | break; |
| 127 | default: | 127 | default: |
| 128 | - ret = s->handle_data(s, pid, devep, data, len); | 128 | + ret = s->handle_data(s, p); |
| 129 | break; | 129 | break; |
| 130 | } | 130 | } |
| 131 | break; | 131 | break; |
| 132 | case USB_TOKEN_OUT: | 132 | case USB_TOKEN_OUT: |
| 133 | - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) | 133 | + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) |
| 134 | return USB_RET_NODEV; | 134 | return USB_RET_NODEV; |
| 135 | - switch(devep) { | 135 | + switch(p->devep) { |
| 136 | case 0: | 136 | case 0: |
| 137 | switch(s->setup_state) { | 137 | switch(s->setup_state) { |
| 138 | case SETUP_STATE_ACK: | 138 | case SETUP_STATE_ACK: |
| @@ -163,7 +163,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | @@ -163,7 +163,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 163 | } | 163 | } |
| 164 | break; | 164 | break; |
| 165 | default: | 165 | default: |
| 166 | - ret = s->handle_data(s, pid, devep, data, len); | 166 | + ret = s->handle_data(s, p); |
| 167 | break; | 167 | break; |
| 168 | } | 168 | } |
| 169 | break; | 169 | break; |
| @@ -191,3 +191,13 @@ int set_usb_string(uint8_t *buf, const char *str) | @@ -191,3 +191,13 @@ int set_usb_string(uint8_t *buf, const char *str) | ||
| 191 | } | 191 | } |
| 192 | return q - buf; | 192 | return q - buf; |
| 193 | } | 193 | } |
| 194 | + | ||
| 195 | +/* Send an internal message to a USB device. */ | ||
| 196 | +void usb_send_msg(USBDevice *dev, int msg) | ||
| 197 | +{ | ||
| 198 | + USBPacket p; | ||
| 199 | + memset(&p, 0, sizeof(p)); | ||
| 200 | + p.pid = msg; | ||
| 201 | + dev->handle_packet(dev, &p); | ||
| 202 | +} | ||
| 203 | + |
hw/usb.h
| @@ -34,6 +34,7 @@ | @@ -34,6 +34,7 @@ | ||
| 34 | #define USB_RET_NAK (-2) | 34 | #define USB_RET_NAK (-2) |
| 35 | #define USB_RET_STALL (-3) | 35 | #define USB_RET_STALL (-3) |
| 36 | #define USB_RET_BABBLE (-4) | 36 | #define USB_RET_BABBLE (-4) |
| 37 | +#define USB_RET_ASYNC (-5) | ||
| 37 | 38 | ||
| 38 | #define USB_SPEED_LOW 0 | 39 | #define USB_SPEED_LOW 0 |
| 39 | #define USB_SPEED_FULL 1 | 40 | #define USB_SPEED_FULL 1 |
| @@ -109,13 +110,12 @@ | @@ -109,13 +110,12 @@ | ||
| 109 | 110 | ||
| 110 | typedef struct USBPort USBPort; | 111 | typedef struct USBPort USBPort; |
| 111 | typedef struct USBDevice USBDevice; | 112 | typedef struct USBDevice USBDevice; |
| 113 | +typedef struct USBPacket USBPacket; | ||
| 112 | 114 | ||
| 113 | /* definition of a USB device */ | 115 | /* definition of a USB device */ |
| 114 | struct USBDevice { | 116 | struct USBDevice { |
| 115 | void *opaque; | 117 | void *opaque; |
| 116 | - int (*handle_packet)(USBDevice *dev, int pid, | ||
| 117 | - uint8_t devaddr, uint8_t devep, | ||
| 118 | - uint8_t *data, int len); | 118 | + int (*handle_packet)(USBDevice *dev, USBPacket *p); |
| 119 | void (*handle_destroy)(USBDevice *dev); | 119 | void (*handle_destroy)(USBDevice *dev); |
| 120 | 120 | ||
| 121 | int speed; | 121 | int speed; |
| @@ -126,8 +126,7 @@ struct USBDevice { | @@ -126,8 +126,7 @@ struct USBDevice { | ||
| 126 | void (*handle_reset)(USBDevice *dev); | 126 | void (*handle_reset)(USBDevice *dev); |
| 127 | int (*handle_control)(USBDevice *dev, int request, int value, | 127 | int (*handle_control)(USBDevice *dev, int request, int value, |
| 128 | int index, int length, uint8_t *data); | 128 | int index, int length, uint8_t *data); |
| 129 | - int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, | ||
| 130 | - uint8_t *data, int len); | 129 | + int (*handle_data)(USBDevice *dev, USBPacket *p); |
| 131 | uint8_t addr; | 130 | uint8_t addr; |
| 132 | char devname[32]; | 131 | char devname[32]; |
| 133 | 132 | ||
| @@ -151,11 +150,54 @@ struct USBPort { | @@ -151,11 +150,54 @@ struct USBPort { | ||
| 151 | struct USBPort *next; /* Used internally by qemu. */ | 150 | struct USBPort *next; /* Used internally by qemu. */ |
| 152 | }; | 151 | }; |
| 153 | 152 | ||
| 153 | +typedef void USBCallback(USBPacket * packet, void *opaque); | ||
| 154 | + | ||
| 155 | +/* Structure used to hold information about an active USB packet. */ | ||
| 156 | +struct USBPacket { | ||
| 157 | + /* Data fields for use by the driver. */ | ||
| 158 | + int pid; | ||
| 159 | + uint8_t devaddr; | ||
| 160 | + uint8_t devep; | ||
| 161 | + uint8_t *data; | ||
| 162 | + int len; | ||
| 163 | + /* Internal use by the USB layer. */ | ||
| 164 | + USBCallback *complete_cb; | ||
| 165 | + void *complete_opaque; | ||
| 166 | + USBCallback *cancel_cb; | ||
| 167 | + void * *cancel_opaque; | ||
| 168 | +}; | ||
| 169 | + | ||
| 170 | +/* Defer completion of a USB packet. The hadle_packet routine should then | ||
| 171 | + return USB_RET_ASYNC. Packets that complete immediately (before | ||
| 172 | + handle_packet returns) should not call this method. */ | ||
| 173 | +static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel, | ||
| 174 | + void * opaque) | ||
| 175 | +{ | ||
| 176 | + p->cancel_cb = cancel; | ||
| 177 | + p->cancel_opaque = opaque; | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +/* Notify the controller that an async packet is complete. This should only | ||
| 181 | + be called for packets previously deferred with usb_defer_packet, and | ||
| 182 | + should never be called from within handle_packet. */ | ||
| 183 | +static inline void usb_packet_complete(USBPacket *p) | ||
| 184 | +{ | ||
| 185 | + p->complete_cb(p, p->complete_opaque); | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +/* Cancel an active packet. The packed must have been deferred with | ||
| 189 | + usb_defer_packet, and not yet completed. */ | ||
| 190 | +static inline void usb_cancel_packet(USBPacket * p) | ||
| 191 | +{ | ||
| 192 | + p->cancel_cb(p, p->cancel_opaque); | ||
| 193 | +} | ||
| 194 | + | ||
| 154 | void usb_attach(USBPort *port, USBDevice *dev); | 195 | void usb_attach(USBPort *port, USBDevice *dev); |
| 155 | -int usb_generic_handle_packet(USBDevice *s, int pid, | ||
| 156 | - uint8_t devaddr, uint8_t devep, | ||
| 157 | - uint8_t *data, int len); | 196 | +int usb_generic_handle_packet(USBDevice *s, USBPacket *p); |
| 158 | int set_usb_string(uint8_t *buf, const char *str); | 197 | int set_usb_string(uint8_t *buf, const char *str); |
| 198 | +void usb_send_msg(USBDevice *dev, int msg); | ||
| 199 | + | ||
| 200 | +void usb_packet_complete(USBPacket *p); | ||
| 159 | 201 | ||
| 160 | /* usb hub */ | 202 | /* usb hub */ |
| 161 | USBDevice *usb_hub_init(int nb_ports); | 203 | USBDevice *usb_hub_init(int nb_ports); |
pc-bios/openbios-esp.diff
0 โ 100644
| 1 | +The ESP SCSI driver currently doesn't check whether a DMA requests has | ||
| 2 | +completed before checking its status. On older qemu versions this works ok | ||
| 3 | +because DMA happens instantly. On never qemu DMA can take an indeterminate | ||
| 4 | +amount of time ooto complete, just like on real hardware. | ||
| 5 | + | ||
| 6 | +The patch below waits for the controller to raise the DMA interrupt after | ||
| 7 | +initiating a DMA request. | ||
| 8 | + | ||
| 9 | +Index: drivers/esp.c | ||
| 10 | +=================================================================== | ||
| 11 | +--- drivers/esp.c (revision 61) | ||
| 12 | ++++ drivers/esp.c (working copy) | ||
| 13 | +@@ -113,6 +113,8 @@ do_command(esp_private_t *esp, sd_privat | ||
| 14 | + esp->espdma.regs->cond_reg = 0; | ||
| 15 | + // Set ATN, issue command | ||
| 16 | + esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA; | ||
| 17 | ++ // Wait for DMA to complete | ||
| 18 | ++ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; | ||
| 19 | + // Check status | ||
| 20 | + status = esp->ll->regs[ESP_STATUS]; | ||
| 21 | + | ||
| 22 | +@@ -129,6 +131,8 @@ do_command(esp_private_t *esp, sd_privat | ||
| 23 | + esp->espdma.regs->cond_reg = DMA_ST_WRITE; | ||
| 24 | + // Transfer | ||
| 25 | + esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA; | ||
| 26 | ++ // Wait for DMA to complete | ||
| 27 | ++ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; | ||
| 28 | + // Check status | ||
| 29 | + status = esp->ll->regs[ESP_STATUS]; | ||
| 30 | + |
pc-bios/openbios-sparc32
No preview for this file type
usb-linux.c
| @@ -114,22 +114,21 @@ static int usb_host_handle_control(USBDevice *dev, | @@ -114,22 +114,21 @@ static int usb_host_handle_control(USBDevice *dev, | ||
| 114 | } | 114 | } |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | -static int usb_host_handle_data(USBDevice *dev, int pid, | ||
| 118 | - uint8_t devep, | ||
| 119 | - uint8_t *data, int len) | 117 | +static int usb_host_handle_data(USBDevice *dev, USBPacket *p) |
| 120 | { | 118 | { |
| 121 | USBHostDevice *s = (USBHostDevice *)dev; | 119 | USBHostDevice *s = (USBHostDevice *)dev; |
| 122 | struct usbdevfs_bulktransfer bt; | 120 | struct usbdevfs_bulktransfer bt; |
| 123 | int ret; | 121 | int ret; |
| 122 | + uint8_t devep = p->devep; | ||
| 124 | 123 | ||
| 125 | /* XXX: optimize and handle all data types by looking at the | 124 | /* XXX: optimize and handle all data types by looking at the |
| 126 | config descriptor */ | 125 | config descriptor */ |
| 127 | - if (pid == USB_TOKEN_IN) | 126 | + if (p->pid == USB_TOKEN_IN) |
| 128 | devep |= 0x80; | 127 | devep |= 0x80; |
| 129 | bt.ep = devep; | 128 | bt.ep = devep; |
| 130 | - bt.len = len; | 129 | + bt.len = p->len; |
| 131 | bt.timeout = 50; | 130 | bt.timeout = 50; |
| 132 | - bt.data = data; | 131 | + bt.data = p->data; |
| 133 | ret = ioctl(s->fd, USBDEVFS_BULK, &bt); | 132 | ret = ioctl(s->fd, USBDEVFS_BULK, &bt); |
| 134 | if (ret < 0) { | 133 | if (ret < 0) { |
| 135 | switch(errno) { | 134 | switch(errno) { |
vl.h
| @@ -1146,6 +1146,11 @@ void do_usb_del(const char *devname); | @@ -1146,6 +1146,11 @@ void do_usb_del(const char *devname); | ||
| 1146 | void usb_info(void); | 1146 | void usb_info(void); |
| 1147 | 1147 | ||
| 1148 | /* scsi-disk.c */ | 1148 | /* scsi-disk.c */ |
| 1149 | +enum scsi_reason { | ||
| 1150 | + SCSI_REASON_DONE, /* Command complete. */ | ||
| 1151 | + SCSI_REASON_DATA /* Transfer complete, more data required. */ | ||
| 1152 | +}; | ||
| 1153 | + | ||
| 1149 | typedef struct SCSIDevice SCSIDevice; | 1154 | typedef struct SCSIDevice SCSIDevice; |
| 1150 | typedef void (*scsi_completionfn)(void *, uint32_t, int); | 1155 | typedef void (*scsi_completionfn)(void *, uint32_t, int); |
| 1151 | 1156 | ||
| @@ -1155,8 +1160,12 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | @@ -1155,8 +1160,12 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, | ||
| 1155 | void scsi_disk_destroy(SCSIDevice *s); | 1160 | void scsi_disk_destroy(SCSIDevice *s); |
| 1156 | 1161 | ||
| 1157 | int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); | 1162 | int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); |
| 1163 | +/* SCSI data transfers are asynchrnonous. However, unlike the block IO | ||
| 1164 | + layer the completion routine may be called directly by | ||
| 1165 | + scsi_{read,write}_data. */ | ||
| 1158 | int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); | 1166 | int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); |
| 1159 | int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); | 1167 | int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); |
| 1168 | +void scsi_cancel_io(SCSIDevice *s); | ||
| 1160 | 1169 | ||
| 1161 | /* lsi53c895a.c */ | 1170 | /* lsi53c895a.c */ |
| 1162 | void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); | 1171 | void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); |