📄 floppy.c.txt
字号:
697 request_done(1);
698 redo_fd_request();
699 }
700
701 /*
702 * We try to read tracks, but if we get too many errors, we
703 * go back to reading just one sector at a time.
704 *
705 * This means we should be able to read a sector even if there
706 * are other bad sectors on this track.
707 */
708 inline void setup_rw_floppy(void)
709 {
710 setup_DMA();
711 do_floppy = rw_interrupt;
712 output_byte(command);
713 if (command != FD_FORMAT) {
714 if (read_track) {
715 output_byte(current_drive);
716 output_byte(track);
717 output_byte(0);
718 output_byte(1);
719 } else {
720 output_byte(head<<2 | current_drive);
721 output_byte(track);
722 output_byte(head);
723 output_byte(sector);
724 }
725 output_byte(2); /* sector size = 512 */
726 output_byte(floppy->sect);
727 output_byte(floppy->gap);
728 output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
729 } else {
730 output_byte(head<<2 | current_drive);
731 output_byte(2);
732 output_byte(floppy->sect);
733 output_byte(floppy->fmt_gap);
734 output_byte(FD_FILL_BYTE);
735 }
736 if (reset)
737 redo_fd_request();
738 }
739
740 /*
741 * This is the routine called after every seek (or recalibrate) interrupt
742 * from the floppy controller. Note that the "unexpected interrupt" routine
743 * also does a recalibrate, but doesn't come here.
744 */
745 static void seek_interrupt(void)
746 {
747 /* sense drive status */
748 output_byte(FD_SENSEI);
749 if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
750 printk(DEVICE_NAME ": seek failed\n");
751 recalibrate = 1;
752 bad_flp_intr();
753 redo_fd_request();
754 return;
755 }
756 current_track = ST1;
757 setup_rw_floppy();
758 }
759
760
761 /*
762 * This routine is called when everything should be correctly set up
763 * for the transfer (ie floppy motor is on and the correct floppy is
764 * selected).
765 */
766 static void transfer(void)
767 {
768 read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
769 (floppy->sect <= MAX_BUFFER_SECTORS);
770
771 configure_fdc_mode();
772
773 if (reset) {
774 redo_fd_request();
775 return;
776 }
777 if (!seek) {
778 setup_rw_floppy();
779 return;
780 }
781
782 do_floppy = seek_interrupt;
783 output_byte(FD_SEEK);
784 if (read_track)
785 output_byte(current_drive);
786 else
787 output_byte((head<<2) | current_drive);
788 output_byte(seek_track);
789 if (reset)
790 redo_fd_request();
791 }
792
793 /*
794 * Special case - used after a unexpected interrupt (or reset)
795 */
796
797 static void recalibrate_floppy(void);
798
799 static void recal_interrupt(void)
800 {
801 output_byte(FD_SENSEI);
802 current_track = NO_TRACK;
803 if (result()!=2 || (ST0 & 0xE0) == 0x60)
804 reset = 1;
805 /* Recalibrate until track 0 is reached. Might help on some errors. */
806 if ((ST0 & 0x10) == 0x10)
807 recalibrate_floppy(); /* FIXME: should limit nr of recalibrates */
808 else
809 redo_fd_request();
810 }
811
812 static void unexpected_floppy_interrupt(void)
813 {
814 current_track = NO_TRACK;
815 output_byte(FD_SENSEI);
816 printk(DEVICE_NAME ": unexpected interrupt\n");
817 if (result()!=2 || (ST0 & 0xE0) == 0x60)
818 reset = 1;
819 else
820 recalibrate = 1;
821 }
822
823 static void recalibrate_floppy(void)
824 {
825 recalibrate = 0;
826 current_track = 0;
827 do_floppy = recal_interrupt;
828 output_byte(FD_RECALIBRATE);
829 output_byte(head<<2 | current_drive);
830 if (reset)
831 redo_fd_request();
832 }
833
834 /*
835 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
836 */
837 static void reset_interrupt(void)
838 {
839 short i;
840
841 for (i=0; i<4; i++) {
842 output_byte(FD_SENSEI);
843 (void) result();
844 }
845 output_byte(FD_SPECIFY);
846 output_byte(cur_spec1); /* hut etc */
847 output_byte(6); /* Head load time =6ms, DMA */
848 configure_fdc_mode(); /* reprogram fdc */
849 if (initial_reset_flag) {
850 initial_reset_flag = 0;
851 recalibrate = 1;
852 reset = 0;
853 return;
854 }
855 if (!recover)
856 redo_fd_request();
857 else {
858 recalibrate_floppy();
859 recover = 0;
860 }
861 }
862
863 /*
864 * reset is done by pulling bit 2 of DOR low for a while.
865 */
866 static void reset_floppy(void)
867 {
868 int i;
869
870 do_floppy = reset_interrupt;
871 reset = 0;
872 current_track = NO_TRACK;
873 cur_spec1 = -1;
874 cur_rate = -1;
875 recalibrate = 1;
876 need_configure = 1;
877 if (!initial_reset_flag)
878 printk("Reset-floppy called\n");
879 cli();
880 outb_p(current_DOR & ~0x04, FD_DOR);
881 for (i=0 ; i<1000 ; i++)
882 __asm__("nop");
883 outb(current_DOR, FD_DOR);
884 sti();
885 }
886
887 static void floppy_shutdown(void)
888 {
889 cli();
890 do_floppy = NULL;
891 request_done(0);
892 recover = 1;
893 reset_floppy();
894 sti();
895 redo_fd_request();
896 }
897
898 static void shake_done(void)
899 {
900 current_track = NO_TRACK;
901 if (inb(FD_DIR) & 0x80)
902 request_done(0);
903 redo_fd_request();
904 }
905
906 static int retry_recal(void (*proc)(void))
907 {
908 output_byte(FD_SENSEI);
909 if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;
910 do_floppy = proc;
911 output_byte(FD_RECALIBRATE);
912 output_byte(head<<2 | current_drive);
913 return 1;
914 }
915
916 static void shake_zero(void)
917 {
918 if (!retry_recal(shake_zero)) shake_done();
919 }
920
921 static void shake_one(void)
922 {
923 if (retry_recal(shake_one)) return;
924 do_floppy = shake_done;
925 output_byte(FD_SEEK);
926 output_byte(head << 2 | current_drive);
927 output_byte(1);
928 }
929
930 static void floppy_ready(void)
931 {
932 if (inb(FD_DIR) & 0x80) {
933 changed_floppies |= 1<<current_drive;
934 buffer_track = -1;
935 if (keep_data[current_drive]) {
936 if (keep_data[current_drive] > 0)
937 keep_data[current_drive]--;
938 } else {
939 if (ftd_msg[current_drive] && current_type[current_drive] != NULL)
940 printk("Disk type is undefined after disk "
941 "change in fd%d\n",current_drive);
942 current_type[current_drive] = NULL;
943 floppy_sizes[current_drive] = MAX_DISK_SIZE;
944 }
945 /* Forcing the drive to seek makes the "media changed" condition go away.
946 * There should be a cleaner solution for that ...
947 */
948 if (!reset && !recalibrate) {
949 if (current_track && current_track != NO_TRACK)
950 do_floppy = shake_zero;
951 else
952 do_floppy = shake_one;
953 output_byte(FD_RECALIBRATE);
954 output_byte(head<<2 | current_drive);
955 return;
956 }
957 }
958 if (reset) {
959 reset_floppy();
960 return;
961 }
962 if (recalibrate) {
963 recalibrate_floppy();
964 return;
965 }
966 transfer();
967 }
968
969 static void setup_format_params(void)
970 {
971 unsigned char *here = (unsigned char *) tmp_floppy_area;
972 int count,head_shift,track_shift,total_shift;
973
974 /* allow for about 30ms for data transport per track */
975 head_shift = floppy->sect / 6;
976 /* a ``cylinder'' is two tracks plus a little stepping time */
977 track_shift = 2 * head_shift + 1;
978 /* count backwards */
979 total_shift = floppy->sect -
980 ((track_shift * track + head_shift * head) % floppy->sect);
981
982 /* XXX: should do a check to see this fits in tmp_floppy_area!! */
983 for (count = 0; count < floppy->sect; count++) {
984 *here++ = track;
985 *here++ = head;
986 *here++ = 1 + (( count + total_shift ) % floppy->sect);
987 *here++ = 2; /* 512 bytes */
988 }
989 }
990
991 static void redo_fd_request(void)
992 {
993 unsigned int block;
994 char * buffer_area;
995 int device;
996
997 if (CURRENT && CURRENT->dev < 0) return;
998
999 repeat:
1000 if (format_status == FORMAT_WAIT)
1001 format_status = FORMAT_BUSY;
1002 if (format_status != FORMAT_BUSY) {
1003 if (!CURRENT) {
1004 if (!fdc_busy)
1005 printk("FDC access conflict!");
1006 fdc_busy = 0;
1007 wake_up(&fdc_wait);
1008 CLEAR_INTR;
1009 return;
1010 }
1011 if (MAJOR(CURRENT->dev) != MAJOR_NR)
1012 panic(DEVICE_NAME ": request list destroyed"); \
1013 if (CURRENT->bh) {
1014 if (!CURRENT->bh->b_lock)
1015 panic(DEVICE_NAME ": block not locked");
1016 }
1017 }
1018 seek = 0;
1019 probing = 0;
1020 device = MINOR(CURRENT_DEVICE);
1021 if (device > 3)
1022 floppy = (device >> 2) + floppy_type;
1023 else { /* Auto-detection */
1024 floppy = current_type[device & 3];
1025 if (!floppy) {
1026 probing = 1;
1027 floppy = base_type[device & 3];
1028 if (!floppy) {
1029 request_done(0);
1030 goto repeat;
1031 }
1032 if (CURRENT_ERRORS & 1)
1033 floppy++;
1034 }
1035 }
1036 if (format_status != FORMAT_BUSY) {
1037 if (current_drive != CURRENT_DEV) {
1038 current_track = NO_TRACK;
1039 current_drive = CURRENT_DEV;
1040 }
1041 block = CURRENT->sector;
1042 if (block+2 > floppy->size) {
1043 request_done(0);
1044 goto repeat;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -