?? floppy.c
字號:
/* This file contains the device dependent part of the driver for the Floppy * Disk Controller (FDC) using the NEC PD765 chip. * * The file contains two entry points: * * floppy_task: main entry when system is brought up * * Changes: * Sep 11, 2005 code cleanup (Andy Tanenbaum) * Dec 01, 2004 floppy driver moved to user-space (Jorrit N. Herder) * Sep 15, 2004 sync alarms/ local timer management (Jorrit N. Herder) * Aug 12, 2003 null seek no interrupt fix (Mike Haertel) * May 14, 2000 d-d/i rewrite (Kees J. Bot) * Apr 04, 1992 device dependent/independent split (Kees J. Bot) * Mar 27, 1992 last details on density checking (Kees J. Bot) * Feb 14, 1992 check drive density on opens only (Andy Tanenbaum) * 1991 len[] / motors / reset / step rate / ... (Bruce Evans) * May 13, 1991 renovated the errors loop (Don Chapman) * 1989 I/O vector to keep up with 1-1 interleave (Bruce Evans) * Jan 06, 1988 allow 1.44 MB diskettes (Al Crew) * Nov 28, 1986 better resetting for 386 (Peter Kay) * Oct 27, 1986 fdc_results fixed for 8 MHz (Jakob Schripsema) */#include "floppy.h"#include <timers.h>#include <ibm/diskparm.h>#include <minix/sysutil.h>#include <minix/syslib.h>/* I/O Ports used by floppy disk task. */#define DOR 0x3F2 /* motor drive control bits */#define FDC_STATUS 0x3F4 /* floppy disk controller status register */#define FDC_DATA 0x3F5 /* floppy disk controller data register */#define FDC_RATE 0x3F7 /* transfer rate register */#define DMA_ADDR 0x004 /* port for low 16 bits of DMA address */#define DMA_TOP 0x081 /* port for top 8 bits of 24-bit DMA addr */#define DMA_COUNT 0x005 /* port for DMA count (count = bytes - 1) */#define DMA_FLIPFLOP 0x00C /* DMA byte pointer flip-flop */#define DMA_MODE 0x00B /* DMA mode port */#define DMA_INIT 0x00A /* DMA init port */#define DMA_RESET_VAL 0x006#define DMA_ADDR_MASK 0xFFFFFF /* mask to verify DMA address is 24-bit *//* Status registers returned as result of operation. */#define ST0 0x00 /* status register 0 */#define ST1 0x01 /* status register 1 */#define ST2 0x02 /* status register 2 */#define ST3 0x00 /* status register 3 (return by DRIVE_SENSE) */#define ST_CYL 0x03 /* slot where controller reports cylinder */#define ST_HEAD 0x04 /* slot where controller reports head */#define ST_SEC 0x05 /* slot where controller reports sector */#define ST_PCN 0x01 /* slot where controller reports present cyl *//* Fields within the I/O ports. *//* Main status register. */#define CTL_BUSY 0x10 /* bit is set when read or write in progress */#define DIRECTION 0x40 /* bit is set when reading data reg is valid */#define MASTER 0x80 /* bit is set when data reg can be accessed *//* Digital output port (DOR). */#define MOTOR_SHIFT 4 /* high 4 bits control the motors in DOR */#define ENABLE_INT 0x0C /* used for setting DOR port *//* ST0. */#define ST0_BITS_TRANS 0xD8 /* check 4 bits of status */#define TRANS_ST0 0x00 /* 4 bits of ST0 for READ/WRITE */#define ST0_BITS_SEEK 0xF8 /* check top 5 bits of seek status */#define SEEK_ST0 0x20 /* top 5 bits of ST0 for SEEK *//* ST1. */#define BAD_SECTOR 0x05 /* if these bits are set in ST1, recalibrate */#define WRITE_PROTECT 0x02 /* bit is set if diskette is write protected *//* ST2. */#define BAD_CYL 0x1F /* if any of these bits are set, recalibrate *//* ST3 (not used). */#define ST3_FAULT 0x80 /* if this bit is set, drive is sick */#define ST3_WR_PROTECT 0x40 /* set when diskette is write protected */#define ST3_READY 0x20 /* set when drive is ready *//* Floppy disk controller command bytes. */#define FDC_SEEK 0x0F /* command the drive to seek */#define FDC_READ 0xE6 /* command the drive to read */#define FDC_WRITE 0xC5 /* command the drive to write */#define FDC_SENSE 0x08 /* command the controller to tell its status */#define FDC_RECALIBRATE 0x07 /* command the drive to go to cyl 0 */#define FDC_SPECIFY 0x03 /* command the drive to accept params */#define FDC_READ_ID 0x4A /* command the drive to read sector identity */#define FDC_FORMAT 0x4D /* command the drive to format a track *//* DMA channel commands. */#define DMA_READ 0x46 /* DMA read opcode */#define DMA_WRITE 0x4A /* DMA write opcode *//* Parameters for the disk drive. */#define HC_SIZE 2880 /* # sectors on largest legal disk (1.44MB) */#define NR_HEADS 0x02 /* two heads (i.e., two tracks/cylinder) */#define MAX_SECTORS 18 /* largest # sectors per track */#define DTL 0xFF /* determines data length (sector size) */#define SPEC2 0x02 /* second parameter to SPECIFY */#define MOTOR_OFF (3*HZ) /* how long to wait before stopping motor */#define WAKEUP (2*HZ) /* timeout on I/O, FDC won't quit. *//* Error codes */#define ERR_SEEK (-1) /* bad seek */#define ERR_TRANSFER (-2) /* bad transfer */#define ERR_STATUS (-3) /* something wrong when getting status */#define ERR_READ_ID (-4) /* bad read id */#define ERR_RECALIBRATE (-5) /* recalibrate didn't work properly */#define ERR_DRIVE (-6) /* something wrong with a drive */#define ERR_WR_PROTECT (-7) /* diskette is write protected */#define ERR_TIMEOUT (-8) /* interrupt timeout *//* No retries on some errors. */#define err_no_retry(err) ((err) <= ERR_WR_PROTECT)/* Encoding of drive type in minor device number. */#define DEV_TYPE_BITS 0x7C /* drive type + 1, if nonzero */#define DEV_TYPE_SHIFT 2 /* right shift to normalize type bits */#define FORMAT_DEV_BIT 0x80 /* bit in minor to turn write into format *//* Miscellaneous. */#define MAX_ERRORS 6 /* how often to try rd/wt before quitting */#define MAX_RESULTS 7 /* max number of bytes controller returns */#define NR_DRIVES 2 /* maximum number of drives */#define DIVISOR 128 /* used for sector size encoding */#define SECTOR_SIZE_CODE 2 /* code to say "512" to the controller */#define TIMEOUT_MICROS 500000L /* microseconds waiting for FDC */#define TIMEOUT_TICKS 30 /* ticks waiting for FDC */#define NT 7 /* number of diskette/drive combinations */#define UNCALIBRATED 0 /* drive needs to be calibrated at next use */#define CALIBRATED 1 /* no calibration needed */#define BASE_SECTOR 1 /* sectors are numbered starting at 1 */#define NO_SECTOR (-1) /* current sector unknown */#define NO_CYL (-1) /* current cylinder unknown, must seek */#define NO_DENS 100 /* current media unknown */#define BSY_IDLE 0 /* busy doing nothing */#define BSY_IO 1 /* busy doing I/O */#define BSY_WAKEN 2 /* got a wakeup call *//* Seven combinations of diskette/drive are supported. * * # Diskette Drive Sectors Tracks Rotation Data-rate Comment * 0 360K 360K 9 40 300 RPM 250 kbps Standard PC DSDD * 1 1.2M 1.2M 15 80 360 RPM 500 kbps AT disk in AT drive * 2 360K 720K 9 40 300 RPM 250 kbps Quad density PC * 3 720K 720K 9 80 300 RPM 250 kbps Toshiba, et al. * 4 360K 1.2M 9 40 360 RPM 300 kbps PC disk in AT drive * 5 720K 1.2M 9 80 360 RPM 300 kbps Toshiba in AT drive * 6 1.44M 1.44M 18 80 300 RPM 500 kbps PS/2, et al. * * In addition, 720K diskettes can be read in 1.44MB drives, but that does * not need a different set of parameters. This combination uses * * 3 720K 1.44M 9 80 300 RPM 250 kbps PS/2, et al. */PRIVATE struct density { u8_t secpt; /* sectors per track */ u8_t cyls; /* tracks per side */ u8_t steps; /* steps per cylinder (2 = double step) */ u8_t test; /* sector to try for density test */ u8_t rate; /* data rate (2=250, 1=300, 0=500 kbps) */ u8_t start; /* motor start (clock ticks) */ u8_t gap; /* gap size */ u8_t spec1; /* first specify byte (SRT/HUT) */} fdensity[NT] = { { 9, 40, 1, 4*9, 2, 4*HZ/8, 0x2A, 0xDF }, /* 360K / 360K */ { 15, 80, 1, 14, 0, 4*HZ/8, 0x1B, 0xDF }, /* 1.2M / 1.2M */ { 9, 40, 2, 2*9, 2, 4*HZ/8, 0x2A, 0xDF }, /* 360K / 720K */ { 9, 80, 1, 4*9, 2, 6*HZ/8, 0x2A, 0xDF }, /* 720K / 720K */ { 9, 40, 2, 2*9, 1, 4*HZ/8, 0x23, 0xDF }, /* 360K / 1.2M */ { 9, 80, 1, 4*9, 1, 4*HZ/8, 0x23, 0xDF }, /* 720K / 1.2M */ { 18, 80, 1, 17, 0, 6*HZ/8, 0x1B, 0xCF }, /* 1.44M / 1.44M */};/* The following table is used with the test_sector array to recognize a * drive/floppy combination. The sector to test has been determined by * looking at the differences in gap size, sectors/track, and double stepping. * This means that types 0 and 3 can't be told apart, only the motor start * time differs. If a read test succeeds then the drive is limited to the * set of densities it can support to avoid unnecessary tests in the future. */#define b(d) (1 << (d)) /* bit for density d. */PRIVATE struct test_order { u8_t t_density; /* floppy/drive type */ u8_t t_class; /* limit drive to this class of densities */} test_order[NT-1] = { { 6, b(3) | b(6) }, /* 1.44M {720K, 1.44M} */ { 1, b(1) | b(4) | b(5) }, /* 1.2M {1.2M, 360K, 720K} */ { 3, b(2) | b(3) | b(6) }, /* 720K {360K, 720K, 1.44M} */ { 4, b(1) | b(4) | b(5) }, /* 360K {1.2M, 360K, 720K} */ { 5, b(1) | b(4) | b(5) }, /* 720K {1.2M, 360K, 720K} */ { 2, b(2) | b(3) }, /* 360K {360K, 720K} */ /* Note that type 0 is missing, type 3 can read/write it too, which is * why the type 3 parameters have been pessimized to be like type 0. */};/* Variables. */PRIVATE struct floppy { /* main drive struct, one entry per drive */ unsigned fl_curcyl; /* current cylinder */ unsigned fl_hardcyl; /* hardware cylinder, as opposed to: */ unsigned fl_cylinder; /* cylinder number addressed */ unsigned fl_sector; /* sector addressed */ unsigned fl_head; /* head number addressed */ char fl_calibration; /* CALIBRATED or UNCALIBRATED */ u8_t fl_density; /* NO_DENS = ?, 0 = 360K; 1 = 360K/1.2M; etc.*/ u8_t fl_class; /* bitmap for possible densities */ timer_t fl_tmr_stop; /* timer to stop motor */ struct device fl_geom; /* Geometry of the drive */ struct device fl_part[NR_PARTITIONS]; /* partition's base & size */} floppy[NR_DRIVES];PRIVATE int irq_hook_id; /* id of irq hook at the kernel */PRIVATE int motor_status; /* bitmap of current motor status */PRIVATE int need_reset; /* set to 1 when controller must be reset */PRIVATE unsigned f_drive; /* selected drive */PRIVATE unsigned f_device; /* selected minor device */PRIVATE struct floppy *f_fp; /* current drive */PRIVATE struct density *f_dp; /* current density parameters */PRIVATE struct density *prev_dp;/* previous density parameters */PRIVATE unsigned f_sectors; /* equal to f_dp->secpt (needed a lot) */PRIVATE u16_t f_busy; /* BSY_IDLE, BSY_IO, BSY_WAKEN */PRIVATE struct device *f_dv; /* device's base and size */PRIVATE struct disk_parameter_s fmt_param; /* parameters for format */PRIVATE u8_t f_results[MAX_RESULTS];/* the controller can give lots of output *//* The floppy uses various timers. These are managed by the floppy driver * itself, because only a single synchronous alarm is available per process. * Besides the 'f_tmr_timeout' timer below, the floppy structure for each * floppy disk drive contains a 'fl_tmr_stop' timer. */PRIVATE timer_t f_tmr_timeout; /* timer for various timeouts */PRIVATE timer_t *f_timers; /* queue of floppy timers */PRIVATE clock_t f_next_timeout; /* the next timeout time */FORWARD _PROTOTYPE( void f_expire_tmrs, (struct driver *dp, message *m_ptr) );FORWARD _PROTOTYPE( void f_set_timer, (timer_t *tp, clock_t delta, tmr_func_t watchdog) );FORWARD _PROTOTYPE( void stop_motor, (timer_t *tp) );FORWARD _PROTOTYPE( void f_timeout, (timer_t *tp) );FORWARD _PROTOTYPE( struct device *f_prepare, (int device) );FORWARD _PROTOTYPE( char *f_name, (void) );FORWARD _PROTOTYPE( void f_cleanup, (void) );FORWARD _PROTOTYPE( int f_transfer, (int proc_nr, int opcode, off_t position, iovec_t *iov, unsigned nr_req) );FORWARD _PROTOTYPE( int dma_setup, (int opcode) );FORWARD _PROTOTYPE( void start_motor, (void) );FORWARD _PROTOTYPE( int seek, (void) );FORWARD _PROTOTYPE( int fdc_transfer, (int opcode) );FORWARD _PROTOTYPE( int fdc_results, (void) );FORWARD _PROTOTYPE( int fdc_command, (u8_t *cmd, int len) );FORWARD _PROTOTYPE( void fdc_out, (int val) );FORWARD _PROTOTYPE( int recalibrate, (void) );FORWARD _PROTOTYPE( void f_reset, (void) );FORWARD _PROTOTYPE( int f_intr_wait, (void) );FORWARD _PROTOTYPE( int read_id, (void) );FORWARD _PROTOTYPE( int f_do_open, (struct driver *dp, message *m_ptr) );FORWARD _PROTOTYPE( void floppy_stop, (struct driver *dp, message *m_ptr));FORWARD _PROTOTYPE( int test_read, (int density) );FORWARD _PROTOTYPE( void f_geometry, (struct partition *entry) );/* Entry points to this driver. */PRIVATE struct driver f_dtab = { f_name, /* current device's name */ f_do_open, /* open or mount request, sense type of diskette */ do_nop, /* nothing on a close */ do_diocntl, /* get or set a partitions geometry */ f_prepare, /* prepare for I/O on a given minor device */ f_transfer, /* do the I/O */ f_cleanup, /* cleanup before sending reply to user process */ f_geometry, /* tell the geometry of the diskette */ floppy_stop, /* floppy cleanup on shutdown */ f_expire_tmrs,/* expire all alarm timers */ nop_cancel, nop_select, NULL, NULL};/*===========================================================================* * floppy_task * *===========================================================================*/PUBLIC void main(){/* Initialize the floppy structure and the timers. */ struct floppy *fp; int s; struct sigaction sa; sa.sa_handler = SIG_MESS; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGTERM,&sa,NULL)<0) panic("floppy","sigaction failed", errno); signal(SIGTERM, SIG_IGN); f_next_timeout = TMR_NEVER; tmr_inittimer(&f_tmr_timeout); for (fp = &floppy[0]; fp < &floppy[NR_DRIVES]; fp++) { fp->fl_curcyl = NO_CYL; fp->fl_density = NO_DENS; fp->fl_class = ~0; tmr_inittimer(&fp->fl_tmr_stop); } /* Set IRQ policy, only request notifications, do not automatically * reenable interrupts. ID return on interrupt is the IRQ line number. */ irq_hook_id = FLOPPY_IRQ; if ((s=sys_irqsetpolicy(FLOPPY_IRQ, 0, &irq_hook_id )) != OK) panic("FLOPPY", "Couldn't set IRQ policy", s); if ((s=sys_irqenable(&irq_hook_id)) != OK) panic("FLOPPY", "Couldn't enable IRQs", s); driver_task(&f_dtab);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -