X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fatapi.h;h=acc90ffe2c6853025bdbc9e864f9d1597b1a5a84;hb=6661dd1d2aa547ae248e816dcd4201bcbcb7fee0;hp=30d829f31fbb222d9b3b7602f573de72de936d01;hpb=f01ef51a3da4c56e7e9019714d489cad2fa52d46;p=palacios.git diff --git a/palacios/src/devices/atapi.h b/palacios/src/devices/atapi.h index 30d829f..acc90ff 100644 --- a/palacios/src/devices/atapi.h +++ b/palacios/src/devices/atapi.h @@ -18,7 +18,6 @@ */ #define ATAPI_PACKET_SIZE 12 -#define ATAPI_BLOCK_SIZE 2048 #include "atapi-types.h" @@ -129,10 +128,10 @@ static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel) static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) { struct ide_drive * drive = get_selected_drive(channel); - int ret = drive->cd_ops->read(drive->data_buf, drive->cd_state.current_lba, drive->private_data); - + int ret = drive->cd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data); + if (ret == -1) { - PrintError("IDE: Error reading CD block (LBA=%x)\n", drive->cd_state.current_lba); + PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba)); return -1; } @@ -148,7 +147,7 @@ static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * ch case 0xa8: // read(12) // Update lba address to point to next block - drive->cd_state.current_lba++; + drive->current_lba++; // read the next block return atapi_read_chunk(dev, channel); @@ -166,35 +165,41 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) { struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf); uint32_t lba = be_to_le_32(cmd->lba); uint16_t xfer_len = be_to_le_16(cmd->xfer_len); - + + PrintDebug("READ10: XferLen=%d\n", xfer_len); + /* Check if cd is ready * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT) */ - + if (xfer_len == 0) { atapi_cmd_nop(dev, channel); return 0; } - if ((lba + xfer_len) > drive->cd_ops->get_capacity(drive->private_data)) { + if (lba + xfer_len > drive->cd_ops->get_capacity(drive->private_data)) { + PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", + lba, xfer_len, lba + xfer_len, + drive->cd_ops->get_capacity(drive->private_data)); atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR); ide_raise_irq(dev, channel); - return 0;} - + return 0; + } + // PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba); - - drive->cd_state.current_lba = lba; - + + drive->current_lba = lba; + // Update the request length value in the cylinder registers - + if (atapi_read_chunk(dev, channel) == -1) { PrintError("IDE: Could not read initial chunk from CD\n"); - return -1; + return -1; } - + drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE; drive->transfer_index = 0; - + // Length of ATAPI buffer sits in cylinder registers // This is weird... The host sets this value to say what it would like to transfer, // if it is larger than the correct size, the device shrinks it to the correct size @@ -202,7 +207,7 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) { PrintError("Could not update initial request length\n"); return -1; } - + ide_raise_irq(dev, channel); return 0; @@ -233,19 +238,57 @@ static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * chann return 0; } +static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) { + struct ide_drive * drive = get_selected_drive(channel); + struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf); + uint16_t alloc_len = be_to_le_16(cmd->alloc_len); + struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf); + int xfer_len = 8; + + memset(resp, 0, sizeof(struct atapi_config_resp)); + + resp->data_len = le_to_be_32(xfer_len - 4); + + if (alloc_len < xfer_len) { + xfer_len = alloc_len; + } + + atapi_setup_cmd_resp(dev, channel, xfer_len); + + return 0; +} + static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) { struct ide_drive * drive = get_selected_drive(channel); struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf); uint16_t alloc_len = be_to_le_16(cmd->alloc_len); - - struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf); - resp->data_len = 10; + int xfer_len = 12; + + memset(resp, 0, sizeof(struct atapi_rd_toc_resp)); + + resp->data_len = le_to_be_16(10); + resp->first_track_num = 1; + resp->last_track_num = 1; + + // we don't handle multi session + // we'll just treat it the same as single session + if ((cmd->format == 0) || (cmd->format == 1)) { + memset(&(resp->track_descs[0]), 0, 8); + + if (alloc_len < xfer_len) { + xfer_len = alloc_len; + } - return -1; + atapi_setup_cmd_resp(dev, channel, xfer_len); + } else { + PrintError("Unhandled Format (%d)\n", cmd->format); + return -1; + } + return 0; } @@ -401,6 +444,22 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan } break; + case 0x46: // get configuration + if (atapi_get_config(dev, channel) == -1) { + PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd); + return -1; + } + break; + + case 0x51: // read disk info + // no-op to keep the Linux CD-ROM driver happy + PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n"); + atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD); + ide_raise_irq(dev, channel); + break; + + + case 0xa8: // read(12) @@ -415,7 +474,7 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan case 0x2b: // seek case 0x1e: // lock door case 0x42: // read sub-channel - case 0x51: // read disk info + case 0x55: // mode select @@ -429,7 +488,7 @@ static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * chan case 0xba: // scan case 0xbb: // set cd speed case 0x4e: // stop play/scan - case 0x46: // ??? + case 0x4a: // ??? default: PrintError("Unhandled ATAPI command %x\n", cmd); @@ -470,16 +529,22 @@ static void atapi_identify_device(struct ide_drive * drive) { // 32 bits access drive_id->dword_io = 1; + // enable DMA access + drive_id->dma_enable = 1; + // enable LBA access drive_id->lba_enable = 1; + drive_id->rw_multiples = 0x80ff; // words 64-70, 54-58 valid - drive_id->buf[53] = 0x0003; + drive_id->field_valid = 0x0007; // DMA + pkg cmd valid // copied from CFA540A drive_id->buf[63] = 0x0103; // variable (DMA stuff) - drive_id->buf[64] = 0x0001; // PIO + //drive_id->buf[63] = 0x0000; // variable (DMA stuff) + + // drive_id->buf[64] = 0x0001; // PIO drive_id->buf[65] = 0x00b4; drive_id->buf[66] = 0x00b4; drive_id->buf[67] = 0x012c; @@ -488,5 +553,8 @@ static void atapi_identify_device(struct ide_drive * drive) { drive_id->buf[71] = 30; // faked drive_id->buf[72] = 30; // faked - drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4 + // drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4 + drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6 + + drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported; }