Commit 98087450722d974b814e19a056ea82699440c0a7
1 parent
02ba45c5
BMDMA support - CDROM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@971 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
546 additions
and
26 deletions
hw/ide.c
... | ... | @@ -299,6 +299,7 @@ typedef struct IDEState { |
299 | 299 | int irq; |
300 | 300 | openpic_t *openpic; |
301 | 301 | PCIDevice *pci_dev; |
302 | + struct BMDMAState *bmdma; | |
302 | 303 | int drive_serial; |
303 | 304 | /* ide regs */ |
304 | 305 | uint8_t feature; |
... | ... | @@ -321,7 +322,11 @@ typedef struct IDEState { |
321 | 322 | int elementary_transfer_size; |
322 | 323 | int io_buffer_index; |
323 | 324 | int lba; |
324 | - /* transfer handling */ | |
325 | + int cd_sector_size; | |
326 | + int atapi_dma; /* true if dma is requested for the packet cmd */ | |
327 | + /* ATA DMA state */ | |
328 | + int io_buffer_size; | |
329 | + /* PIO transfer handling */ | |
325 | 330 | int req_nb_sectors; /* number of sectors per interrupt */ |
326 | 331 | EndTransferFunc *end_transfer_func; |
327 | 332 | uint8_t *data_ptr; |
... | ... | @@ -329,6 +334,34 @@ typedef struct IDEState { |
329 | 334 | uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; |
330 | 335 | } IDEState; |
331 | 336 | |
337 | +#define BM_STATUS_DMAING 0x01 | |
338 | +#define BM_STATUS_ERROR 0x02 | |
339 | +#define BM_STATUS_INT 0x04 | |
340 | + | |
341 | +#define BM_CMD_START 0x01 | |
342 | +#define BM_CMD_READ 0x08 | |
343 | + | |
344 | +typedef int IDEDMAFunc(IDEState *s, | |
345 | + target_phys_addr_t phys_addr, | |
346 | + int transfer_size1); | |
347 | + | |
348 | +typedef struct BMDMAState { | |
349 | + uint8_t cmd; | |
350 | + uint8_t status; | |
351 | + uint32_t addr; | |
352 | + /* current transfer state */ | |
353 | + IDEState *ide_if; | |
354 | + IDEDMAFunc *dma_cb; | |
355 | +} BMDMAState; | |
356 | + | |
357 | +typedef struct PCIIDEState { | |
358 | + PCIDevice dev; | |
359 | + IDEState ide_if[4]; | |
360 | + BMDMAState bmdma[2]; | |
361 | +} PCIIDEState; | |
362 | + | |
363 | +static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); | |
364 | + | |
332 | 365 | static void padstr(char *str, const char *src, int len) |
333 | 366 | { |
334 | 367 | int i, v; |
... | ... | @@ -554,6 +587,59 @@ static void ide_sector_read(IDEState *s) |
554 | 587 | } |
555 | 588 | } |
556 | 589 | |
590 | +static int ide_read_dma_cb(IDEState *s, | |
591 | + target_phys_addr_t phys_addr, | |
592 | + int transfer_size1) | |
593 | +{ | |
594 | + int len, transfer_size, n; | |
595 | + int64_t sector_num; | |
596 | + | |
597 | + transfer_size = transfer_size1; | |
598 | + while (transfer_size > 0) { | |
599 | + len = s->io_buffer_size - s->io_buffer_index; | |
600 | + if (len <= 0) { | |
601 | + /* transfert next data */ | |
602 | + n = s->nsector; | |
603 | + if (n == 0) | |
604 | + break; | |
605 | + if (n > MAX_MULT_SECTORS) | |
606 | + n = MAX_MULT_SECTORS; | |
607 | + sector_num = ide_get_sector(s); | |
608 | + bdrv_read(s->bs, sector_num, s->io_buffer, n); | |
609 | + s->io_buffer_index = 0; | |
610 | + s->io_buffer_size = n * 512; | |
611 | + len = s->io_buffer_size; | |
612 | + sector_num += n; | |
613 | + ide_set_sector(s, sector_num); | |
614 | + s->nsector -= n; | |
615 | + } | |
616 | + if (len > transfer_size) | |
617 | + len = transfer_size; | |
618 | + cpu_physical_memory_write(phys_addr, | |
619 | + s->io_buffer + s->io_buffer_index, len); | |
620 | + s->io_buffer_index += len; | |
621 | + transfer_size -= len; | |
622 | + phys_addr += len; | |
623 | + } | |
624 | + if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) { | |
625 | + s->status = READY_STAT | SEEK_STAT; | |
626 | + ide_set_irq(s); | |
627 | +#ifdef DEBUG_IDE_ATAPI | |
628 | + printf("dma status=0x%x\n", s->status); | |
629 | +#endif | |
630 | + return 0; | |
631 | + } | |
632 | + return transfer_size1 - transfer_size; | |
633 | +} | |
634 | + | |
635 | +static void ide_sector_read_dma(IDEState *s) | |
636 | +{ | |
637 | + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; | |
638 | + s->io_buffer_index = 0; | |
639 | + s->io_buffer_size = 0; | |
640 | + ide_dma_start(s, ide_read_dma_cb); | |
641 | +} | |
642 | + | |
557 | 643 | static void ide_sector_write(IDEState *s) |
558 | 644 | { |
559 | 645 | int64_t sector_num; |
... | ... | @@ -582,6 +668,62 @@ static void ide_sector_write(IDEState *s) |
582 | 668 | ide_set_irq(s); |
583 | 669 | } |
584 | 670 | |
671 | +static int ide_write_dma_cb(IDEState *s, | |
672 | + target_phys_addr_t phys_addr, | |
673 | + int transfer_size1) | |
674 | +{ | |
675 | + int len, transfer_size, n; | |
676 | + int64_t sector_num; | |
677 | + | |
678 | + transfer_size = transfer_size1; | |
679 | + for(;;) { | |
680 | + len = s->io_buffer_size - s->io_buffer_index; | |
681 | + if (len == 0) { | |
682 | + n = s->io_buffer_size >> 9; | |
683 | + sector_num = ide_get_sector(s); | |
684 | + bdrv_write(s->bs, sector_num, s->io_buffer, | |
685 | + s->io_buffer_size >> 9); | |
686 | + sector_num += n; | |
687 | + ide_set_sector(s, sector_num); | |
688 | + s->nsector -= n; | |
689 | + n = s->nsector; | |
690 | + if (n == 0) { | |
691 | + /* end of transfer */ | |
692 | + s->status = READY_STAT | SEEK_STAT; | |
693 | + ide_set_irq(s); | |
694 | + return 0; | |
695 | + } | |
696 | + if (n > MAX_MULT_SECTORS) | |
697 | + n = MAX_MULT_SECTORS; | |
698 | + s->io_buffer_index = 0; | |
699 | + s->io_buffer_size = n * 512; | |
700 | + len = s->io_buffer_size; | |
701 | + } | |
702 | + if (transfer_size <= 0) | |
703 | + break; | |
704 | + if (len > transfer_size) | |
705 | + len = transfer_size; | |
706 | + cpu_physical_memory_read(phys_addr, | |
707 | + s->io_buffer + s->io_buffer_index, len); | |
708 | + s->io_buffer_index += len; | |
709 | + transfer_size -= len; | |
710 | + phys_addr += len; | |
711 | + } | |
712 | + return transfer_size1 - transfer_size; | |
713 | +} | |
714 | + | |
715 | +static void ide_sector_write_dma(IDEState *s) | |
716 | +{ | |
717 | + int n; | |
718 | + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; | |
719 | + n = s->nsector; | |
720 | + if (n > MAX_MULT_SECTORS) | |
721 | + n = MAX_MULT_SECTORS; | |
722 | + s->io_buffer_index = 0; | |
723 | + s->io_buffer_size = n * 512; | |
724 | + ide_dma_start(s, ide_write_dma_cb); | |
725 | +} | |
726 | + | |
585 | 727 | static void ide_atapi_cmd_ok(IDEState *s) |
586 | 728 | { |
587 | 729 | s->error = 0; |
... | ... | @@ -627,6 +769,41 @@ static inline int ube32_to_cpu(const uint8_t *buf) |
627 | 769 | return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; |
628 | 770 | } |
629 | 771 | |
772 | +static void lba_to_msf(uint8_t *buf, int lba) | |
773 | +{ | |
774 | + lba += 150; | |
775 | + buf[0] = (lba / 75) / 60; | |
776 | + buf[1] = (lba / 75) % 60; | |
777 | + buf[2] = lba % 75; | |
778 | +} | |
779 | + | |
780 | +static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, | |
781 | + int sector_size) | |
782 | +{ | |
783 | + switch(sector_size) { | |
784 | + case 2048: | |
785 | + bdrv_read(bs, (int64_t)lba << 2, buf, 4); | |
786 | + break; | |
787 | + case 2352: | |
788 | + /* sync bytes */ | |
789 | + buf[0] = 0x00; | |
790 | + memset(buf + 1, 0xff, 11); | |
791 | + buf += 12; | |
792 | + /* MSF */ | |
793 | + lba_to_msf(buf, lba); | |
794 | + buf[3] = 0x01; /* mode 1 data */ | |
795 | + buf += 4; | |
796 | + /* data */ | |
797 | + bdrv_read(bs, (int64_t)lba << 2, buf, 4); | |
798 | + buf += 2048; | |
799 | + /* ECC */ | |
800 | + memset(buf, 0, 288); | |
801 | + break; | |
802 | + default: | |
803 | + break; | |
804 | + } | |
805 | +} | |
806 | + | |
630 | 807 | /* The whole ATAPI transfer logic is handled in this function */ |
631 | 808 | static void ide_atapi_cmd_reply_end(IDEState *s) |
632 | 809 | { |
... | ... | @@ -648,15 +825,15 @@ static void ide_atapi_cmd_reply_end(IDEState *s) |
648 | 825 | #endif |
649 | 826 | } else { |
650 | 827 | /* see if a new sector must be read */ |
651 | - if (s->lba != -1 && s->io_buffer_index >= 2048) { | |
652 | - bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); | |
828 | + if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { | |
829 | + cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); | |
653 | 830 | s->lba++; |
654 | 831 | s->io_buffer_index = 0; |
655 | 832 | } |
656 | 833 | if (s->elementary_transfer_size > 0) { |
657 | 834 | /* there are some data left to transmit in this elementary |
658 | 835 | transfer */ |
659 | - size = 2048 - s->io_buffer_index; | |
836 | + size = s->cd_sector_size - s->io_buffer_index; | |
660 | 837 | if (size > s->elementary_transfer_size) |
661 | 838 | size = s->elementary_transfer_size; |
662 | 839 | ide_transfer_start(s, s->io_buffer + s->io_buffer_index, |
... | ... | @@ -685,8 +862,8 @@ static void ide_atapi_cmd_reply_end(IDEState *s) |
685 | 862 | s->elementary_transfer_size = size; |
686 | 863 | /* we cannot transmit more than one sector at a time */ |
687 | 864 | if (s->lba != -1) { |
688 | - if (size > (2048 - s->io_buffer_index)) | |
689 | - size = (2048 - s->io_buffer_index); | |
865 | + if (size > (s->cd_sector_size - s->io_buffer_index)) | |
866 | + size = (s->cd_sector_size - s->io_buffer_index); | |
690 | 867 | } |
691 | 868 | ide_transfer_start(s, s->io_buffer + s->io_buffer_index, |
692 | 869 | size, ide_atapi_cmd_reply_end); |
... | ... | @@ -716,21 +893,88 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) |
716 | 893 | } |
717 | 894 | |
718 | 895 | /* start a CD-CDROM read command */ |
719 | -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) | |
896 | +static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, | |
897 | + int sector_size) | |
720 | 898 | { |
721 | -#ifdef DEBUG_IDE_ATAPI | |
722 | - printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); | |
723 | -#endif | |
724 | 899 | s->lba = lba; |
725 | - s->packet_transfer_size = nb_sectors * 2048; | |
900 | + s->packet_transfer_size = nb_sectors * sector_size; | |
726 | 901 | s->elementary_transfer_size = 0; |
727 | - s->io_buffer_index = 2048; | |
902 | + s->io_buffer_index = sector_size; | |
903 | + s->cd_sector_size = sector_size; | |
728 | 904 | |
729 | 905 | s->status = READY_STAT; |
730 | 906 | ide_atapi_cmd_reply_end(s); |
731 | 907 | } |
732 | 908 | |
909 | +/* ATAPI DMA support */ | |
910 | +static int ide_atapi_cmd_read_dma_cb(IDEState *s, | |
911 | + target_phys_addr_t phys_addr, | |
912 | + int transfer_size1) | |
913 | +{ | |
914 | + int len, transfer_size; | |
915 | + | |
916 | + transfer_size = transfer_size1; | |
917 | + while (transfer_size > 0) { | |
918 | + if (s->packet_transfer_size <= 0) | |
919 | + break; | |
920 | + len = s->cd_sector_size - s->io_buffer_index; | |
921 | + if (len <= 0) { | |
922 | + /* transfert next data */ | |
923 | + cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); | |
924 | + s->lba++; | |
925 | + s->io_buffer_index = 0; | |
926 | + len = s->cd_sector_size; | |
927 | + } | |
928 | + if (len > transfer_size) | |
929 | + len = transfer_size; | |
930 | + cpu_physical_memory_write(phys_addr, | |
931 | + s->io_buffer + s->io_buffer_index, len); | |
932 | + s->packet_transfer_size -= len; | |
933 | + s->io_buffer_index += len; | |
934 | + transfer_size -= len; | |
935 | + phys_addr += len; | |
936 | + } | |
937 | + if (s->packet_transfer_size <= 0) { | |
938 | + s->status = READY_STAT; | |
939 | + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; | |
940 | + ide_set_irq(s); | |
941 | +#ifdef DEBUG_IDE_ATAPI | |
942 | + printf("dma status=0x%x\n", s->status); | |
943 | +#endif | |
944 | + return 0; | |
945 | + } | |
946 | + return transfer_size1 - transfer_size; | |
947 | +} | |
948 | + | |
949 | +/* start a CD-CDROM read command with DMA */ | |
950 | +/* XXX: test if DMA is available */ | |
951 | +static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, | |
952 | + int sector_size) | |
953 | +{ | |
954 | + s->lba = lba; | |
955 | + s->packet_transfer_size = nb_sectors * sector_size; | |
956 | + s->io_buffer_index = sector_size; | |
957 | + s->cd_sector_size = sector_size; | |
958 | + | |
959 | + s->status = READY_STAT | DRQ_STAT; | |
960 | + ide_dma_start(s, ide_atapi_cmd_read_dma_cb); | |
961 | +} | |
962 | + | |
963 | +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, | |
964 | + int sector_size) | |
965 | +{ | |
966 | +#ifdef DEBUG_IDE_ATAPI | |
967 | + printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); | |
968 | +#endif | |
969 | + if (s->atapi_dma) { | |
970 | + ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); | |
971 | + } else { | |
972 | + ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); | |
973 | + } | |
974 | +} | |
975 | + | |
733 | 976 | /* same toc as bochs. Return -1 if error or the toc length */ |
977 | +/* XXX: check this */ | |
734 | 978 | static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) |
735 | 979 | { |
736 | 980 | uint8_t *q; |
... | ... | @@ -739,8 +983,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) |
739 | 983 | if (start_track > 1 && start_track != 0xaa) |
740 | 984 | return -1; |
741 | 985 | q = buf + 2; |
742 | - *q++ = 1; | |
743 | - *q++ = 1; | |
986 | + *q++ = 1; /* first session */ | |
987 | + *q++ = 1; /* last session */ | |
744 | 988 | if (start_track <= 1) { |
745 | 989 | *q++ = 0; /* reserved */ |
746 | 990 | *q++ = 0x14; /* ADR, control */ |
... | ... | @@ -765,9 +1009,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) |
765 | 1009 | nb_sectors = s->nb_sectors >> 2; |
766 | 1010 | if (msf) { |
767 | 1011 | *q++ = 0; /* reserved */ |
768 | - *q++ = ((nb_sectors + 150) / 75) / 60; | |
769 | - *q++ = ((nb_sectors + 150) / 75) % 60; | |
770 | - *q++ = (nb_sectors + 150) % 75; | |
1012 | + lba_to_msf(q, nb_sectors); | |
1013 | + q += 3; | |
771 | 1014 | } else { |
772 | 1015 | cpu_to_ube32(q, nb_sectors); |
773 | 1016 | q += 4; |
... | ... | @@ -777,6 +1020,75 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) |
777 | 1020 | return len; |
778 | 1021 | } |
779 | 1022 | |
1023 | +/* mostly same info as PearPc */ | |
1024 | +static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, | |
1025 | + int session_num) | |
1026 | +{ | |
1027 | + uint8_t *q; | |
1028 | + int nb_sectors, len; | |
1029 | + | |
1030 | + q = buf + 2; | |
1031 | + *q++ = 1; /* first session */ | |
1032 | + *q++ = 1; /* last session */ | |
1033 | + | |
1034 | + *q++ = 1; /* session number */ | |
1035 | + *q++ = 0x14; /* data track */ | |
1036 | + *q++ = 0; /* track number */ | |
1037 | + *q++ = 0xa0; /* lead-in */ | |
1038 | + *q++ = 0; /* min */ | |
1039 | + *q++ = 0; /* sec */ | |
1040 | + *q++ = 0; /* frame */ | |
1041 | + *q++ = 0; | |
1042 | + *q++ = 1; /* first track */ | |
1043 | + *q++ = 0x00; /* disk type */ | |
1044 | + *q++ = 0x00; | |
1045 | + | |
1046 | + *q++ = 1; /* session number */ | |
1047 | + *q++ = 0x14; /* data track */ | |
1048 | + *q++ = 0; /* track number */ | |
1049 | + *q++ = 0xa1; | |
1050 | + *q++ = 0; /* min */ | |
1051 | + *q++ = 0; /* sec */ | |
1052 | + *q++ = 0; /* frame */ | |
1053 | + *q++ = 0; | |
1054 | + *q++ = 1; /* last track */ | |
1055 | + *q++ = 0x00; | |
1056 | + *q++ = 0x00; | |
1057 | + | |
1058 | + *q++ = 1; /* session number */ | |
1059 | + *q++ = 0x14; /* data track */ | |
1060 | + *q++ = 0; /* track number */ | |
1061 | + *q++ = 0xa2; /* lead-out */ | |
1062 | + *q++ = 0; /* min */ | |
1063 | + *q++ = 0; /* sec */ | |
1064 | + *q++ = 0; /* frame */ | |
1065 | + nb_sectors = s->nb_sectors >> 2; | |
1066 | + if (msf) { | |
1067 | + *q++ = 0; /* reserved */ | |
1068 | + lba_to_msf(q, nb_sectors); | |
1069 | + q += 3; | |
1070 | + } else { | |
1071 | + cpu_to_ube32(q, nb_sectors); | |
1072 | + q += 4; | |
1073 | + } | |
1074 | + | |
1075 | + *q++ = 1; /* session number */ | |
1076 | + *q++ = 0x14; /* ADR, control */ | |
1077 | + *q++ = 0; /* track number */ | |
1078 | + *q++ = 1; /* point */ | |
1079 | + *q++ = 0; /* min */ | |
1080 | + *q++ = 0; /* sec */ | |
1081 | + *q++ = 0; /* frame */ | |
1082 | + *q++ = 0; | |
1083 | + *q++ = 0; | |
1084 | + *q++ = 0; | |
1085 | + *q++ = 0; | |
1086 | + | |
1087 | + len = q - buf; | |
1088 | + cpu_to_ube16(buf, len - 2); | |
1089 | + return len; | |
1090 | +} | |
1091 | + | |
780 | 1092 | static void ide_atapi_cmd(IDEState *s) |
781 | 1093 | { |
782 | 1094 | const uint8_t *packet; |
... | ... | @@ -921,7 +1233,48 @@ static void ide_atapi_cmd(IDEState *s) |
921 | 1233 | ASC_LOGICAL_BLOCK_OOR); |
922 | 1234 | break; |
923 | 1235 | } |
924 | - ide_atapi_cmd_read(s, lba, nb_sectors); | |
1236 | + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); | |
1237 | + } | |
1238 | + break; | |
1239 | + case GPCMD_READ_CD: | |
1240 | + { | |
1241 | + int nb_sectors, lba, transfer_request; | |
1242 | + | |
1243 | + if (!bdrv_is_inserted(s->bs)) { | |
1244 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1245 | + ASC_MEDIUM_NOT_PRESENT); | |
1246 | + break; | |
1247 | + } | |
1248 | + nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; | |
1249 | + lba = ube32_to_cpu(packet + 2); | |
1250 | + if (nb_sectors == 0) { | |
1251 | + ide_atapi_cmd_ok(s); | |
1252 | + break; | |
1253 | + } | |
1254 | + if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { | |
1255 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
1256 | + ASC_LOGICAL_BLOCK_OOR); | |
1257 | + break; | |
1258 | + } | |
1259 | + transfer_request = packet[9]; | |
1260 | + switch(transfer_request & 0xf8) { | |
1261 | + case 0x00: | |
1262 | + /* nothing */ | |
1263 | + ide_atapi_cmd_ok(s); | |
1264 | + break; | |
1265 | + case 0x10: | |
1266 | + /* normal read */ | |
1267 | + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); | |
1268 | + break; | |
1269 | + case 0xf8: | |
1270 | + /* read all data */ | |
1271 | + ide_atapi_cmd_read(s, lba, nb_sectors, 2352); | |
1272 | + break; | |
1273 | + default: | |
1274 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
1275 | + ASC_INV_FIELD_IN_CMD_PACKET); | |
1276 | + break; | |
1277 | + } | |
925 | 1278 | } |
926 | 1279 | break; |
927 | 1280 | case GPCMD_SEEK: |
... | ... | @@ -995,6 +1348,12 @@ static void ide_atapi_cmd(IDEState *s) |
995 | 1348 | buf[3] = 0x01; |
996 | 1349 | ide_atapi_cmd_reply(s, 12, max_len); |
997 | 1350 | break; |
1351 | + case 2: | |
1352 | + len = cdrom_read_toc_raw(s, buf, msf, start_track); | |
1353 | + if (len < 0) | |
1354 | + goto error_cmd; | |
1355 | + ide_atapi_cmd_reply(s, len, max_len); | |
1356 | + break; | |
998 | 1357 | default: |
999 | 1358 | error_cmd: |
1000 | 1359 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
... | ... | @@ -1169,6 +1528,18 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
1169 | 1528 | n = s->req_nb_sectors; |
1170 | 1529 | ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); |
1171 | 1530 | break; |
1531 | + case WIN_READDMA: | |
1532 | + case WIN_READDMA_ONCE: | |
1533 | + if (!s->bs) | |
1534 | + goto abort_cmd; | |
1535 | + ide_sector_read_dma(s); | |
1536 | + break; | |
1537 | + case WIN_WRITEDMA: | |
1538 | + case WIN_WRITEDMA_ONCE: | |
1539 | + if (!s->bs) | |
1540 | + goto abort_cmd; | |
1541 | + ide_sector_write_dma(s); | |
1542 | + break; | |
1172 | 1543 | case WIN_READ_NATIVE_MAX: |
1173 | 1544 | ide_set_sector(s, s->nb_sectors - 1); |
1174 | 1545 | s->status = READY_STAT; |
... | ... | @@ -1185,6 +1556,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
1185 | 1556 | /* XXX: valid for CDROM ? */ |
1186 | 1557 | switch(s->feature) { |
1187 | 1558 | case 0x02: /* write cache enable */ |
1559 | + case 0x03: /* set transfer mode */ | |
1188 | 1560 | case 0x82: /* write cache disable */ |
1189 | 1561 | case 0xaa: /* read look-ahead enable */ |
1190 | 1562 | case 0x55: /* read look-ahead disable */ |
... | ... | @@ -1216,9 +1588,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
1216 | 1588 | case WIN_PACKETCMD: |
1217 | 1589 | if (!s->is_cdrom) |
1218 | 1590 | goto abort_cmd; |
1219 | - /* DMA or overlapping commands not supported */ | |
1220 | - if ((s->feature & 0x03) != 0) | |
1591 | + /* overlapping commands not supported */ | |
1592 | + if (s->feature & 0x02) | |
1221 | 1593 | goto abort_cmd; |
1594 | + s->atapi_dma = s->feature & 1; | |
1222 | 1595 | s->nsector = 1; |
1223 | 1596 | ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, |
1224 | 1597 | ide_atapi_cmd); |
... | ... | @@ -1549,11 +1922,6 @@ void isa_ide_init(int iobase, int iobase2, int irq, |
1549 | 1922 | /***********************************************************/ |
1550 | 1923 | /* PCI IDE definitions */ |
1551 | 1924 | |
1552 | -typedef struct PCIIDEState { | |
1553 | - PCIDevice dev; | |
1554 | - IDEState ide_if[4]; | |
1555 | -} PCIIDEState; | |
1556 | - | |
1557 | 1925 | static void ide_map(PCIDevice *pci_dev, int region_num, |
1558 | 1926 | uint32_t addr, uint32_t size, int type) |
1559 | 1927 | { |
... | ... | @@ -1578,6 +1946,155 @@ static void ide_map(PCIDevice *pci_dev, int region_num, |
1578 | 1946 | } |
1579 | 1947 | } |
1580 | 1948 | |
1949 | +/* XXX: full callback usage to prepare non blocking I/Os support - | |
1950 | + error handling */ | |
1951 | +static void ide_dma_loop(BMDMAState *bm) | |
1952 | +{ | |
1953 | + struct { | |
1954 | + uint32_t addr; | |
1955 | + uint32_t size; | |
1956 | + } prd; | |
1957 | + target_phys_addr_t cur_addr; | |
1958 | + int len, i, len1; | |
1959 | + | |
1960 | + cur_addr = bm->addr; | |
1961 | + /* at most one page to avoid hanging if erroneous parameters */ | |
1962 | + for(i = 0; i < 512; i++) { | |
1963 | + cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8); | |
1964 | + prd.addr = le32_to_cpu(prd.addr); | |
1965 | + prd.size = le32_to_cpu(prd.size); | |
1966 | +#ifdef DEBUG_IDE | |
1967 | + printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n", | |
1968 | + (int)cur_addr, prd.addr, prd.size); | |
1969 | +#endif | |
1970 | + len = prd.size & 0xfffe; | |
1971 | + if (len == 0) | |
1972 | + len = 0x10000; | |
1973 | + while (len > 0) { | |
1974 | + len1 = bm->dma_cb(bm->ide_if, prd.addr, len); | |
1975 | + if (len1 == 0) | |
1976 | + goto the_end; | |
1977 | + prd.addr += len1; | |
1978 | + len -= len1; | |
1979 | + } | |
1980 | + /* end of transfer */ | |
1981 | + if (prd.size & 0x80000000) | |
1982 | + break; | |
1983 | + cur_addr += 8; | |
1984 | + } | |
1985 | + /* end of transfer */ | |
1986 | + the_end: | |
1987 | + bm->status &= ~BM_STATUS_DMAING; | |
1988 | + bm->status |= BM_STATUS_INT; | |
1989 | + bm->dma_cb = NULL; | |
1990 | + bm->ide_if = NULL; | |
1991 | +} | |
1992 | + | |
1993 | +static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) | |
1994 | +{ | |
1995 | + BMDMAState *bm = s->bmdma; | |
1996 | + if(!bm) | |
1997 | + return; | |
1998 | + bm->ide_if = s; | |
1999 | + bm->dma_cb = dma_cb; | |
2000 | + if (bm->status & BM_STATUS_DMAING) { | |
2001 | + ide_dma_loop(bm); | |
2002 | + } | |
2003 | +} | |
2004 | + | |
2005 | +static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr) | |
2006 | +{ | |
2007 | + BMDMAState *bm = opaque; | |
2008 | + uint32_t val; | |
2009 | + val = bm->cmd; | |
2010 | +#ifdef DEBUG_IDE | |
2011 | + printf("%s: 0x%08x\n", __func__, val); | |
2012 | +#endif | |
2013 | + return val; | |
2014 | +} | |
2015 | + | |
2016 | +static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) | |
2017 | +{ | |
2018 | + BMDMAState *bm = opaque; | |
2019 | +#ifdef DEBUG_IDE | |
2020 | + printf("%s: 0x%08x\n", __func__, val); | |
2021 | +#endif | |
2022 | + if (!(val & BM_CMD_START)) { | |
2023 | + /* XXX: do it better */ | |
2024 | + bm->status &= ~BM_STATUS_DMAING; | |
2025 | + bm->cmd = val & 0x09; | |
2026 | + } else { | |
2027 | + bm->status |= BM_STATUS_DMAING; | |
2028 | + bm->cmd = val & 0x09; | |
2029 | + /* start dma transfer if possible */ | |
2030 | + if (bm->dma_cb) | |
2031 | + ide_dma_loop(bm); | |
2032 | + } | |
2033 | +} | |
2034 | + | |
2035 | +static uint32_t bmdma_status_readb(void *opaque, uint32_t addr) | |
2036 | +{ | |
2037 | + BMDMAState *bm = opaque; | |
2038 | + uint32_t val; | |
2039 | + val = bm->status; | |
2040 | +#ifdef DEBUG_IDE | |
2041 | + printf("%s: 0x%08x\n", __func__, val); | |
2042 | +#endif | |
2043 | + return val; | |
2044 | +} | |
2045 | + | |
2046 | +static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val) | |
2047 | +{ | |
2048 | + BMDMAState *bm = opaque; | |
2049 | +#ifdef DEBUG_IDE | |
2050 | + printf("%s: 0x%08x\n", __func__, val); | |
2051 | +#endif | |
2052 | + bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); | |
2053 | +} | |
2054 | + | |
2055 | +static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) | |
2056 | +{ | |
2057 | + BMDMAState *bm = opaque; | |
2058 | + uint32_t val; | |
2059 | + val = bm->addr; | |
2060 | +#ifdef DEBUG_IDE | |
2061 | + printf("%s: 0x%08x\n", __func__, val); | |
2062 | +#endif | |
2063 | + return val; | |
2064 | +} | |
2065 | + | |
2066 | +static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) | |
2067 | +{ | |
2068 | + BMDMAState *bm = opaque; | |
2069 | +#ifdef DEBUG_IDE | |
2070 | + printf("%s: 0x%08x\n", __func__, val); | |
2071 | +#endif | |
2072 | + bm->addr = val & ~3; | |
2073 | +} | |
2074 | + | |
2075 | +static void bmdma_map(PCIDevice *pci_dev, int region_num, | |
2076 | + uint32_t addr, uint32_t size, int type) | |
2077 | +{ | |
2078 | + PCIIDEState *d = (PCIIDEState *)pci_dev; | |
2079 | + int i; | |
2080 | + | |
2081 | + for(i = 0;i < 2; i++) { | |
2082 | + BMDMAState *bm = &d->bmdma[i]; | |
2083 | + d->ide_if[2 * i].bmdma = bm; | |
2084 | + d->ide_if[2 * i + 1].bmdma = bm; | |
2085 | + | |
2086 | + register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); | |
2087 | + register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm); | |
2088 | + | |
2089 | + register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm); | |
2090 | + register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm); | |
2091 | + | |
2092 | + register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); | |
2093 | + register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); | |
2094 | + addr += 8; | |
2095 | + } | |
2096 | +} | |
2097 | + | |
1581 | 2098 | /* hd_table must contain 4 block drivers */ |
1582 | 2099 | void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) |
1583 | 2100 | { |
... | ... | @@ -1610,6 +2127,8 @@ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) |
1610 | 2127 | PCI_ADDRESS_SPACE_IO, ide_map); |
1611 | 2128 | pci_register_io_region((PCIDevice *)d, 3, 0x4, |
1612 | 2129 | PCI_ADDRESS_SPACE_IO, ide_map); |
2130 | + pci_register_io_region((PCIDevice *)d, 4, 0x10, | |
2131 | + PCI_ADDRESS_SPACE_IO, bmdma_map); | |
1613 | 2132 | |
1614 | 2133 | pci_conf[0x3d] = 0x01; // interrupt on pin 1 |
1615 | 2134 | |
... | ... | @@ -1640,7 +2159,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) |
1640 | 2159 | pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage |
1641 | 2160 | pci_conf[0x0e] = 0x00; // header_type |
1642 | 2161 | |
1643 | - /* XXX: must add BMDMA support to be fully compliant */ | |
2162 | + pci_register_io_region((PCIDevice *)d, 4, 0x10, | |
2163 | + PCI_ADDRESS_SPACE_IO, bmdma_map); | |
1644 | 2164 | |
1645 | 2165 | ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); |
1646 | 2166 | ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); | ... | ... |