⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 floppy.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 4 页
字号:
349 
350 static void floppy_on(unsigned int nr)
351 {
352         unsigned char mask = 0x10 << nr;
353 
354         del_timer(motor_off_timer + nr);
355         if (mask & running)
356                 floppy_select(nr);
357         if (!(mask & current_DOR)) {
358                 del_timer(motor_on_timer + nr);
359                 motor_on_timer[nr].expires = HZ;
360                 add_timer(motor_on_timer + nr);
361         }
362         current_DOR &= 0xFC;
363         current_DOR |= mask;
364         current_DOR |= nr;
365         outb(current_DOR,FD_DOR);
366 }
367 
368 static void floppy_off(unsigned int nr)
369 {
370         del_timer(motor_off_timer+nr);
371         motor_off_timer[nr].expires = 3*HZ;
372         add_timer(motor_off_timer+nr);
373 }
374 
375 void request_done(int uptodate)
376 {
377         timer_active &= ~(1 << FLOPPY_TIMER);
378         if (format_status != FORMAT_BUSY)
379                 end_request(uptodate);
380         else {
381                 format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
382                 wake_up(&format_done);
383         }
384 }
385 
386 /*
387  * floppy-change is never called from an interrupt, so we can relax a bit
388  * here, sleep etc. Note that floppy-on tries to set current_DOR to point
389  * to the desired drive, but it will probably not survive the sleep if
390  * several floppies are used at the same time: thus the loop.
391  */
392 int floppy_change(struct buffer_head * bh)
393 {
394         unsigned int mask = 1 << (bh->b_dev & 0x03);
395 
396         if (MAJOR(bh->b_dev) != MAJOR_NR) {
397                 printk("floppy_changed: not a floppy\n");
398                 return 0;
399         }
400         if (fake_change & mask) {
401                 buffer_track = -1;
402                 fake_change &= ~mask;
403 /* omitting the next line breaks formatting in a horrible way ... */
404                 changed_floppies &= ~mask;
405                 return 1;
406         }
407         if (changed_floppies & mask) {
408                 buffer_track = -1;
409                 changed_floppies &= ~mask;
410                 recalibrate = 1;
411                 return 1;
412         }
413         if (!bh)
414                 return 0;
415         if (bh->b_dirt)
416                 ll_rw_block(WRITE, 1, &bh);
417         else {
418                 buffer_track = -1;
419                 bh->b_uptodate = 0;
420                 ll_rw_block(READ, 1, &bh);
421         }
422         wait_on_buffer(bh);
423         if (changed_floppies & mask) {
424                 changed_floppies &= ~mask;
425                 recalibrate = 1;
426                 return 1;
427         }
428         return 0;
429 }
430 
431 #define copy_buffer(from,to) \
432 __asm__("cld ; rep ; movsl" \
433         : \
434         :"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
435         :"cx","di","si")
436 
437 static void setup_DMA(void)
438 {
439         unsigned long addr,count;
440         unsigned char dma_code;
441 
442         dma_code = DMA_WRITE;
443         if (command == FD_READ)
444                 dma_code = DMA_READ;
445         if (command == FD_FORMAT) {
446                 addr = (long) tmp_floppy_area;
447                 count = floppy->sect*4;
448         } else {
449                 addr = (long) CURRENT->buffer;
450                 count = 1024;
451         }
452         if (read_track) {
453 /* mark buffer-track bad, in case all this fails.. */
454                 buffer_drive = buffer_track = -1;
455                 count = floppy->sect*floppy->head*512;
456                 addr = (long) floppy_track_buffer;
457         } else if (addr >= LAST_DMA_ADDR) {
458                 addr = (long) tmp_floppy_area;
459                 if (command == FD_WRITE)
460                         copy_buffer(CURRENT->buffer,tmp_floppy_area);
461         }
462         cli();
463         disable_dma(FLOPPY_DMA);
464         clear_dma_ff(FLOPPY_DMA);
465         set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
466         set_dma_addr(FLOPPY_DMA, addr);
467         set_dma_count(FLOPPY_DMA, count);
468         enable_dma(FLOPPY_DMA);
469         sti();
470 }
471 
472 static void output_byte(char byte)
473 {
474         int counter;
475         unsigned char status;
476 
477         if (reset)
478                 return;
479         for(counter = 0 ; counter < 10000 ; counter++) {
480                 status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
481                 if (status == STATUS_READY) {
482                         outb(byte,FD_DATA);
483                         return;
484                 }
485         }
486         current_track = NO_TRACK;
487         reset = 1;
488         printk("Unable to send byte to FDC\n");
489 }
490 
491 static int result(void)
492 {
493         int i = 0, counter, status;
494 
495         if (reset)
496                 return -1;
497         for (counter = 0 ; counter < 10000 ; counter++) {
498                 status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
499                 if (status == STATUS_READY) {
500                         return i;
501                 }
502                 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
503                         if (i >= MAX_REPLIES) {
504                                 printk("floppy_stat reply overrun\n");
505                                 break;
506                         }
507                         reply_buffer[i++] = inb_p(FD_DATA);
508                 }
509         }
510         reset = 1;
511         current_track = NO_TRACK;
512         printk("Getstatus times out\n");
513         return -1;
514 }
515 
516 static void bad_flp_intr(void)
517 {
518         int errors;
519 
520         current_track = NO_TRACK;
521         if (format_status == FORMAT_BUSY)
522                 errors = ++format_errors;
523         else if (!CURRENT) {
524                 printk(DEVICE_NAME ": no current request\n");
525                 reset = recalibrate = 1;
526                 return;
527         } else
528                 errors = ++CURRENT->errors;
529         if (errors > MAX_ERRORS) {
530                 request_done(0);
531         }
532         if (errors > MAX_ERRORS/2)
533                 reset = 1;
534         else
535                 recalibrate = 1;
536 }       
537 
538 
539 /* Set perpendicular mode as required, based on data rate, if supported.
540  * 82077 Untested! 1Mbps data rate only possible with 82077-1.
541  * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
542  */
543 static inline void perpendicular_mode(unsigned char rate)
544 {
545         if (fdc_version == FDC_TYPE_82077) {
546                 output_byte(FD_PERPENDICULAR);
547                 if (rate & 0x40) {
548                         unsigned char r = rate & 0x03;
549                         if (r == 0)
550                                 output_byte(2); /* perpendicular, 500 kbps */
551                         else if (r == 3)
552                                 output_byte(3); /* perpendicular, 1Mbps */
553                         else {
554                                 printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
555                                 reset = 1;
556                         }
557                 } else
558                         output_byte(0);         /* conventional mode */
559         } else {
560                 if (rate & 0x40) {
561                         printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
562                         reset = 1;
563                 }
564         }
565 } /* perpendicular_mode */
566 
567 
568 /*
569  * This has only been tested for the case fdc_version == FDC_TYPE_STD.
570  * In case you have a 82077 and want to test it, you'll have to compile
571  * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for
572  * recognizing drives with vertical recording support.
573  */
574 static void configure_fdc_mode(void)
575 {
576         if (need_configure && (fdc_version == FDC_TYPE_82077)) {
577                 /* Enhanced version with FIFO & vertical recording. */
578                 output_byte(FD_CONFIGURE);
579                 output_byte(0);
580                 output_byte(0x1A);      /* FIFO on, polling off, 10 byte threshold */
581                 output_byte(0);         /* precompensation from track 0 upwards */
582                 need_configure = 0;
583                 printk(DEVICE_NAME ": FIFO enabled\n");
584         }
585         if (cur_spec1 != floppy->spec1) {
586                 cur_spec1 = floppy->spec1;
587                 output_byte(FD_SPECIFY);
588                 output_byte(cur_spec1);         /* hut etc */
589                 output_byte(6);                 /* Head load time =6ms, DMA */
590         }
591         if (cur_rate != floppy->rate) {
592                 /* use bit 6 of floppy->rate to indicate perpendicular mode */
593                 perpendicular_mode(floppy->rate);
594                 outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR);
595         }
596 } /* configure_fdc_mode */
597 
598 
599 static void tell_sector(int nr)
600 {
601         if (nr!=7) {
602                 printk(" -- FDC reply errror");
603                 reset = 1;
604         } else
605                 printk(": track %d, head %d, sector %d", reply_buffer[3],
606                         reply_buffer[4], reply_buffer[5]);
607 } /* tell_sector */
608 
609 
610 /*
611  * Ok, this interrupt is called after a DMA read/write has succeeded
612  * or failed, so we check the results, and copy any buffers.
613  * hhb: Added better error reporting.
614  */
615 static void rw_interrupt(void)
616 {
617         char * buffer_area;
618         int nr;
619         char bad;
620 
621         nr = result();
622         /* check IC to find cause of interrupt */
623         switch ((ST0 & ST0_INTR)>>6) {
624                 case 1: /* error occured during command execution */
625                         bad = 1;
626                         if (ST1 & ST1_WP) {
627                                 printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive);
628                                 request_done(0);
629                                 bad = 0;
630                         } else if (ST1 & ST1_OR) {
631                                 if (ftd_msg[ST0 & ST0_DS])
632                                         printk(DEVICE_NAME ": Over/Underrun - retrying\n");
633                                 /* could continue from where we stopped, but ... */
634                                 bad = 0;
635                         } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {
636                                 printk(DEVICE_NAME " %d: ", ST0 & ST0_DS);
637                                 if (ST0 & ST0_ECE) {
638                                         printk("Recalibrate failed!");
639                                 } else if (ST2 & ST2_CRC) {
640                                         printk("data CRC error");
641                                         tell_sector(nr);
642                                 } else if (ST1 & ST1_CRC) {
643                                         printk("CRC error");
644                                         tell_sector(nr);
645                                 } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
646                                         if (!probing) {
647                                                 printk("sector not found");
648                                                 tell_sector(nr);
649                                         } else
650                                                 printk("probe failed...");
651                                 } else if (ST2 & ST2_WC) {      /* seek error */
652                                         printk("wrong cylinder");
653                                 } else if (ST2 & ST2_BC) {      /* cylinder marked as bad */
654                                         printk("bad cylinder");
655                                 } else {
656                                         printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3);
657                                 }
658                                 printk("\n");
659 
660                         }
661                         if (bad)
662                                 bad_flp_intr();
663                         redo_fd_request();
664                         return;
665                 case 2: /* invalid command given */
666                         printk(DEVICE_NAME ": Invalid FDC command given!\n");
667                         request_done(0);
668                         return;
669                 case 3:
670                         printk(DEVICE_NAME ": Abnormal termination caused by polling\n");
671                         bad_flp_intr();
672                         redo_fd_request();
673                         return;
674                 default: /* (0) Normal command termination */
675                         break;
676         }
677 
678         if (probing) {
679                 int drive = MINOR(CURRENT->dev);
680 
681                 if (ftd_msg[drive])
682                         printk("Auto-detected floppy type %s in fd%d\n",
683                             floppy->name,drive);
684                 current_type[drive] = floppy;
685                 floppy_sizes[drive] = floppy->size >> 1;
686                 probing = 0;
687         }
688         if (read_track) {
689                 buffer_track = seek_track;
690                 buffer_drive = current_drive;
691                 buffer_area = floppy_track_buffer +
692                         ((sector-1 + head*floppy->sect)<<9);
693                 copy_buffer(buffer_area,CURRENT->buffer);
694         } else if (command == FD_READ &&
695                 (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR)
696                 copy_buffer(tmp_floppy_area,CURRENT->buffer);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -