📄 floppy.c.txt
字号:
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 + -