{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" },
{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" },
{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" },
{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" },
{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" },
{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" }
};
static struct floppy_struct floppy_type[32] = {
{ 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },
{ 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" },
{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },
{ 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" },
{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" },
{ 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" },
{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" },
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },
{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },
{ 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" },
{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" },
{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" },
{ 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" },
{ 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" },
{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },
{ 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },
{ 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" },
{ 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" },
{ 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },
{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" },
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" },
{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" },
{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" },
{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" },
{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" },
{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" },
{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" },
{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" },
{ 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" },
{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" },
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" },
{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" },
};
static int disk_change(int drive)
static inline int is_selected(int dor, int unit)
static int set_dor(int fdc, char mask, char data)
static void twaddle(void)
{
if (DP->select_delay)
return;
fd_outb(FDCS->dor & ~(0x10<<UNIT(current_drive)), FD_DOR);
fd_outb(FDCS->dor, FD_DOR);
DRS->select_date = jiffies;
}
static void reset_fdc_info(int mode)
{
}
static void set_fdc(int drive)
{
static int _lock_fdc(int drive, int interruptible, int line)
{
}
#define lock_fdc(drive,interruptible) _lock_fdc(drive,interruptible, __LINE__)
#define LOCK_FDC(drive,interruptible) \
if (lock_fdc(drive,interruptible)) return -EINTR;
static inline void unlock_fdc(void)
static void motor_off_callback(unsigned long nr)
static void floppy_off(unsigned int drive)
static void scandrives(void)
static void schedule_bh( void (*handler)(void*) )
static struct timer_list fd_timer;
static void main_command_interrupt(void)
{
del_timer(&fd_timer);
cont->interrupt();
}
static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
{
}
static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED;
static int hlt_disabled;
static void floppy_disable_hlt(void)
static void floppy_enable_hlt(void)
{
unsigned long flags;
spin_lock_irqsave(&floppy_hlt_lock, flags);
if (hlt_disabled){
hlt_disabled=0;
#ifdef HAVE_DISABLE_HLT
enable_hlt();
#endif
}
spin_unlock_irqrestore(&floppy_hlt_lock, flags);
}
static void setup_DMA(void)
static void show_floppy(void);
static int wait_til_ready(void)
static int output_byte(char byte)
{
int status;
if ((status = wait_til_ready()) < 0)
return -1;
if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY){
fd_outb(byte,FD_DATA);
#ifdef FLOPPY_SANITY_CHECK
output_log[output_log_pos].data = byte;
output_log[output_log_pos].status = status;
output_log[output_log_pos].jiffies = jiffies;
output_log_pos = (output_log_pos + 1) % OLOGSIZE;
#endif
return 0;
}
FDCS->reset = 1;
if (!initialising) {
DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
byte, fdc, status);
show_floppy();
}
return -1;
}
#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
static int result(void)
#define MORE_OUTPUT -2
static int need_more_output(void)
{
int status;
if ((status = wait_til_ready()) < 0)
return -1;
if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY)
return MORE_OUTPUT;
return result();
}
static inline void perpendicular_mode(void)
{
unsigned char perp_mode;
if (raw_cmd->rate & 0x40){
switch(raw_cmd->rate & 3){
case 0:
perp_mode=2;
break;
case 3:
perp_mode=3;
break;
default:
DPRINT("Invalid data rate for perpendicular mode!\n");
cont->done(0);
FDCS->reset = 1;
return;
}
} else
perp_mode = 0;
if (FDCS->perp_mode == perp_mode)
return;
if (FDCS->version >= FDC_82077_ORIG) {
output_byte(FD_PERPENDICULAR);
output_byte(perp_mode);
FDCS->perp_mode = perp_mode;
} else if (perp_mode) {
DPRINT("perpendicular mode not supported by this FDC.\n");
}
}
static int fifo_depth = 0xa;
static int no_fifo;
static int fdc_configure(void)
{
output_byte(FD_CONFIGURE);
if (need_more_output() != MORE_OUTPUT)
return 0;
output_byte(0);
output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
output_byte(0);
return 1;
}
#define NOMINAL_DTR 500
static void fdc_specify(void)
{
unsigned char spec1, spec2;
unsigned long srt, hlt, hut;
unsigned long dtr = NOMINAL_DTR;
unsigned long scale_dtr = NOMINAL_DTR;
int hlt_max_code = 0x7f;
int hut_max_code = 0xf;
if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
fdc_configure();
FDCS->need_configure = 0;
}
switch (raw_cmd->rate & 0x03) {
case 3:
dtr = 1000;
break;
case 1:
dtr = 300;
if (FDCS->version >= FDC_82078) {
output_byte(FD_DRIVESPEC);
if (need_more_output() == MORE_OUTPUT) {
output_byte(UNIT(current_drive));
output_byte(0xc0);
}
}
break;
case 2:
dtr = 250;
break;
}
if (FDCS->version >= FDC_82072) {
scale_dtr = dtr;
hlt_max_code = 0x00;
hut_max_code = 0x0;
}
srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;
if( slow_floppy ) {
srt = srt / 4;
}
SUPBOUND(srt, 0xf);
INFBOUND(srt, 0);
hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;
if (hlt < 0x01)
hlt = 0x01;
else if (hlt > 0x7f)
hlt = hlt_max_code;
hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;
if (hut < 0x1)
hut = 0x1;
else if (hut > 0xf)
hut = hut_max_code;
spec1 = (srt << 4) | hut;
spec2 = (hlt << 1) | (use_virtual_dma & 1);
if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
output_byte(FD_SPECIFY);
output_byte(FDCS->spec1 = spec1);
output_byte(FDCS->spec2 = spec2);
}
}
static int fdc_dtr(void)
{
if ((raw_cmd->rate & 3) == FDCS->dtr)
return 0;
fd_outb(raw_cmd->rate & 3, FD_DCR);
FDCS->dtr = raw_cmd->rate & 3;
return(fd_wait_for_completion(jiffies+2UL*HZ/100,
(timeout_fn) floppy_ready));
}
static void tell_sector(void)
{
printk(": track %d, head %d, sector %d, size %d",
R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
}
static int interpret_errors(void)
{
char bad;
if (inr!=7) {
DPRINT("-- FDC reply error");
FDCS->reset = 1;
return 1;
}
switch (ST0 & ST0_INTR) {
case 0x40:
if (ST1 & ST1_EOC)
return 0;
bad = 1;
if (ST1 & ST1_WP) {
DPRINT("Drive is write protected\n");
CLEARF(FD_DISK_WRITABLE);
cont->done(0);
bad = 2;
} else if (ST1 & ST1_ND) {
SETF(FD_NEED_TWADDLE);
} else if (ST1 & ST1_OR) {
if (DP->flags & FTD_MSG)
DPRINT("Over/Underrun - retrying\n");
bad = 0;
}else if (*errors >= DP->max_errors.reporting){
DPRINT("");
if (ST0 & ST0_ECE) {
printk("Recalibrate failed!");
} else if (ST2 & ST2_CRC) {
printk("data CRC error");
tell_sector();
} else if (ST1 & ST1_CRC) {
printk("CRC error");
tell_sector();
} else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
if (!probing) {
printk("sector not found");
tell_sector();
} else
printk("probe failed...");
} else if (ST2 & ST2_WC) {
printk("wrong cylinder");
} else if (ST2 & ST2_BC) {
printk("bad cylinder");
} else {
printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2);
tell_sector();
}
printk("\n");
}
if (ST2 & ST2_WC || ST2 & ST2_BC)
DRS->track = NEED_2_RECAL;
return bad;
case 0x80:
DPRINT("Invalid FDC command given!\n");
cont->done(0);
return 2;
case 0xc0:
DPRINT("Abnormal termination caused by polling\n");
cont->error();
return 2;
default:
return 0;
}
}
static void setup_rw_floppy(void)
static int blind_seek;
static void seek_interrupt(void)
static void check_wp(void)
static void seek_floppy(void)
static void recal_interrupt(void)
static void print_result(char *message, int inr)
void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
static void recalibrate_floppy(void)
static void reset_interrupt(void)
static void reset_fdc(void)
static void show_floppy(void)
static void floppy_shutdown(void)
static int start_motor(void (*function)(void) )
static void floppy_ready(void)
static void floppy_start(void)
static int wait_til_done(void (*handler)(void), int interruptible)
static void generic_done(int result)
static void generic_success(void)
static void generic_failure(void)
static void success_and_wakeup(void)
static int next_valid_format(void)
static void bad_flp_intr(void)
static void set_floppy(kdev_t device)
static void format_interrupt(void)
static void setup_format_params(int track)
static void redo_format(void)
static int do_format(kdev_t device, struct format_descr *tmp_format_req)
static void request_done(int uptodate)
static void rw_interrupt(void)
static int buffer_chain_size(void)
static int transfer_size(int ssize, int max_sector, int max_size)
static void copy_buffer(int ssize, int max_sector, int max_sector_2)
static int make_raw_rw_request(void)
static void redo_fd_request(void)
static void do_fd_request(request_queue_t * q)
static struct cont_t poll_cont={
success_and_wakeup,
floppy_ready,
generic_failure,
generic_done };
static int poll_drive(int interruptible, int flag)
{
int ret;
raw_cmd = &default_raw_cmd;
raw_cmd->flags= flag;
raw_cmd->track=0;
raw_cmd->cmd_count=0;
cont = &poll_cont;
#ifdef DCL_DEBUG
if (DP->flags & FD_DEBUG){
DPRINT("setting NEWCHANGE in poll_drive\n");
}
#endif
SETF(FD_DISK_NEWCHANGE);
WAIT(floppy_ready);
return ret;
}
static inline int fd_copyout(void *param, const void *address, unsigned long size)
{
return copy_to_user(param,address, size) ? -EFAULT : 0;
}
static inline int fd_copyin(void *param, void *address, unsigned long size)
{
return copy_from_user(address, param, size) ? -EFAULT : 0;
}
static inline const char *drive_name(int type, int drive)
static void raw_cmd_done(int flag)
static inline int raw_cmd_copyout(int cmd, char *param,
struct floppy_raw_cmd *ptr)
static void raw_cmd_free(struct floppy_raw_cmd **ptr)
static int raw_cmd_ioctl(int cmd, void *param)
static int invalidate_drive(kdev_t rdev)
static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
int drive, int type, kdev_t device)
{
int cnt;
if (g->sect <= 0 ||
g->head <= 0 ||
g->track <= 0 ||
g->track > UDP->tracks>>STRETCH(g) ||
(g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0)
return -EINVAL;
if (type){
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
LOCK_FDC(drive,1);
for (cnt = 0; cnt < N_DRIVE; cnt++){
if (ITYPE(drive_state[cnt].fd_device) == type &&
drive_state[cnt].fd_ref)
set_bit(drive, &fake_change);
}
floppy_type[type] = *g;
floppy_type[type].name="user format";
for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
floppy_sizes[cnt]= floppy_sizes[cnt+0x80]=
(floppy_type[type].size+1)>>1;
process_fd_request();
for (cnt = 0; cnt < N_DRIVE; cnt++){
if (ITYPE(drive_state[cnt].fd_device) == type &&
drive_state[cnt].fd_ref)
check_disk_change(
MKDEV(FLOPPY_MAJOR,
drive_state[cnt].fd_device));
}
} else {
LOCK_FDC(drive,1);
if (cmd != FDDEFPRM)
CALL(poll_drive(1, FD_RAW_NEED_DISK));
user_params[drive] = *g;
if (buffer_drive == drive)
SUPBOUND(buffer_max, user_params[drive].sect);
current_type[drive] = &user_params[drive];
floppy_sizes[drive] = (user_params[drive].size+1) >> 1;
if (cmd == FDDEFPRM)
DRS->keep_data = -1;
else
DRS->keep_data = 1;
if (DRS->maxblock > user_params[drive].sect || DRS->maxtrack)
invalidate_drive(device);
else
process_fd_request();
}
return 0;
}
static int ioctl_table[]= {
FDCLRPRM,
FDSETPRM,
FDDEFPRM,
FDGETPRM,
FDMSGON,
FDMSGOFF,
FDFMTBEG,
FDFMTTRK,
FDFMTEND,
FDSETEMSGTRESH,
FDFLUSH,
FDSETMAXERRS,
FDGETMAXERRS,
FDGETDRVTYP,
FDSETDRVPRM,
FDGETDRVPRM,
FDGETDRVSTAT,
FDPOLLDRVSTAT,
FDRESET,
FDGETFDCSTAT,
FDWERRORCLR,
FDWERRORGET,
FDRAWCMD,
FDEJECT,
FDTWADDLE
};
static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long param)
{
#define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data)
#define OUT(c,x) case c: outparam = (const char *) (x); break
#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
int i,drive,type;
kdev_t device;
int ret;
int size;
union inparam {
struct floppy_struct g;
struct format_descr f;
struct floppy_max_errors max_errors;
struct floppy_drive_params dp;
} inparam;
const char *outparam;
device = inode->i_rdev;
switch (cmd) {
case BLKROSET:
case BLKROGET:
case BLKRASET:
case BLKRAGET:
case BLKFLSBUF:
return blk_ioctl(device, cmd, param);
}
type = TYPE(device);
drive = DRIVE(device);
if (cmd == CDROMEJECT ||
cmd == 0x6470 ) {
DPRINT("obsolete eject ioctl\n");
DPRINT("please use floppycontrol --eject\n");
cmd = FDEJECT;
}
switch(cmd) {
struct floppy_struct *g;
case HDIO_GETGEO:
{
struct hd_geometry loc;
ECALL(get_floppy_geometry(drive, type, &g));
loc.heads = g->head;
loc.sectors = g->sect;
loc.cylinders = g->track;
loc.start = 0;
return _COPYOUT(loc);
}
case BLKGETSIZE:
ECALL(get_floppy_geometry(drive, type, &g));
return put_user(g->size, (unsigned long *) param);
case BLKGETSIZE64:
ECALL(get_floppy_geometry(drive, type, &g));
return put_user((u64)g->size << 9, (u64 *) param);
}
if ((cmd & 0xff00) == 0x0200) {
ECALL(normalize_ioctl(&cmd, &size));
} else
return -EINVAL;
if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
return -EPERM;
CLEARSTRUCT(&inparam);
if (_IOC_DIR(cmd) & _IOC_WRITE)
ECALL(fd_copyin((void *)param, &inparam, size))
switch (cmd) {
case FDEJECT:
if (UDRS->fd_ref != 1)
return -EBUSY;
LOCK_FDC(drive,1);
ret=fd_eject(UNIT(drive));
USETF(FD_DISK_CHANGED);
USETF(FD_VERIFY);
process_fd_request();
return ret;
case FDCLRPRM:
LOCK_FDC(drive,1);
current_type[drive] = NULL;
floppy_sizes[drive] = MAX_DISK_SIZE;
UDRS->keep_data = 0;
return invalidate_drive(device);
case FDSETPRM:
case FDDEFPRM:
return set_geometry(cmd, & inparam.g,
drive, type, device);
case FDGETPRM:
ECALL(get_floppy_geometry(drive, type,
(struct floppy_struct**)
&outparam));
break;
case FDMSGON:
UDP->flags |= FTD_MSG;
return 0;
case FDMSGOFF:
UDP->flags &= ~FTD_MSG;
return 0;
case FDFMTBEG:
LOCK_FDC(drive,1);
CALL(poll_drive(1, FD_RAW_NEED_DISK));
ret = UDRS->flags;
process_fd_request();
if (ret & FD_VERIFY)
return -ENODEV;
if (!(ret & FD_DISK_WRITABLE))
return -EROFS;
return 0;
case FDFMTTRK:
if (UDRS->fd_ref != 1)
return -EBUSY;
return do_format(device, &inparam.f);
case FDFMTEND:
case FDFLUSH:
LOCK_FDC(drive,1);
return invalidate_drive(device);
case FDSETEMSGTRESH:
UDP->max_errors.reporting =
(unsigned short) (param & 0x0f);
return 0;
OUT(FDGETMAXERRS, &UDP->max_errors);
IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
case FDGETDRVTYP:
outparam = drive_name(type,drive);
SUPBOUND(size,strlen(outparam)+1);
break;
IN(FDSETDRVPRM, UDP, dp);
OUT(FDGETDRVPRM, UDP);
case FDPOLLDRVSTAT:
LOCK_FDC(drive,1);
CALL(poll_drive(1, FD_RAW_NEED_DISK));
process_fd_request();
OUT(FDGETDRVSTAT, UDRS);
case FDRESET:
return user_reset_fdc(drive, (int)param, 1);
OUT(FDGETFDCSTAT,UFDCS);
case FDWERRORCLR:
CLEARSTRUCT(UDRWE);
return 0;
OUT(FDWERRORGET,UDRWE);
case FDRAWCMD:
if (type)
return -EINVAL;
LOCK_FDC(drive,1);
set_floppy(device);
CALL(i = raw_cmd_ioctl(cmd,(void *) param));
process_fd_request();
return i;
case FDTWADDLE:
LOCK_FDC(drive,1);
twaddle();
process_fd_request();
return 0;
default:
return -EINVAL;
}
if (_IOC_DIR(cmd) & _IOC_READ)
return fd_copyout((void *)param, outparam, size);
else
return 0;
#undef OUT
#undef IN
}
static int floppy_release(struct inode * inode, struct file * filp)
#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0)
static int floppy_open(struct inode * inode, struct file * filp)
static int check_floppy_change(kdev_t dev)
static int floppy_revalidate(kdev_t dev)
static struct block_device_operations floppy_fops = {
owner: THIS_MODULE,
open: floppy_open,
release: floppy_release,
ioctl: fd_ioctl,
check_media_change: check_floppy_change,
revalidate: floppy_revalidate,
};
static char __init get_fdc_version(void)
{
int r;
output_byte(FD_DUMPREGS);
if (FDCS->reset)
return FDC_NONE;
if ((r = result()) <= 0x00)
return FDC_NONE;
if ((r==1) && (reply_buffer[0] == 0x80)){
printk(KERN_INFO "FDC %d is an 8272A\n",fdc);
return FDC_8272A;
}
if (r != 10) {
printk("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
fdc, r);
return FDC_UNKNOWN;
}
if (!fdc_configure()) {
printk(KERN_INFO "FDC %d is an 82072\n",fdc);
return FDC_82072;
}
output_byte(FD_PERPENDICULAR);
if (need_more_output() == MORE_OUTPUT) {
output_byte(0);
} else {
printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
return FDC_82072A;
}
output_byte(FD_UNLOCK);
r = result();
if ((r == 1) && (reply_buffer[0] == 0x80)){
printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
return FDC_82077_ORIG;
}
if ((r != 1) || (reply_buffer[0] != 0x00)) {
printk("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
fdc, r);
return FDC_UNKNOWN;
}
output_byte(FD_PARTID);
r = result();
if (r != 1) {
printk("FDC %d init: PARTID: unexpected return of %d bytes.\n",
fdc, r);
return FDC_UNKNOWN;
}
if (reply_buffer[0] == 0x80) {
printk(KERN_INFO "FDC %d is a post-1991 82077\n",fdc);
return FDC_82077;
}
switch (reply_buffer[0] >> 5) {
case 0x0:
printk(KERN_INFO "FDC %d is an 82078.\n",fdc);
return FDC_82078;
case 0x1:
printk(KERN_INFO "FDC %d is a 44pin 82078\n",fdc);
return FDC_82078;
case 0x2:
printk(KERN_INFO "FDC %d is a S82078B\n", fdc);
return FDC_S82078B;
case 0x3:
printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n", fdc);
return FDC_87306;
default:
printk(KERN_INFO "FDC %d init: 82078 variant with unknown PARTID=%d.\n",
fdc, reply_buffer[0] >> 5);
return FDC_82078_UNKN;
}
}
static int __init floppy_setup(char *str)
{
int i;
int param;
int ints[11];
str = get_options(str,ARRAY_SIZE(ints),ints);
if (str) {
for (i=0; i< ARRAY_SIZE(config_params); i++){
if (strcmp(str,config_params[i].name) == 0){
if (ints[0])
param = ints[1];
else
param = config_params[i].def_param;
if (config_params[i].fn)
config_params[i].
fn(ints,param,
config_params[i].param2);
if (config_params[i].var) {
DPRINT("%s=%d\n", str, param);
*config_params[i].var = param;
}
return 1;
}
}
}
if (str) {
DPRINT("unknown floppy option [%s]\n", str);
DPRINT("allowed options are:");
for (i=0; i< ARRAY_SIZE(config_params); i++)
printk(" %s",config_params[i].name);
printk("\n");
} else
DPRINT("botched floppy option\n");
DPRINT("Read linux/Documentation/floppy.txt\n");
return 0;
}
int __init floppy_init(void)
{
int i,unit,drive;
raw_cmd = NULL;
devfs_handle = devfs_mk_dir (NULL, "floppy", NULL);
if (devfs_register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return -EBUSY;
}
for (i=0; i<256; i++) {
if (ITYPE(i))
floppy_sizes[i] = (floppy_type[ITYPE(i)].size+1) >> 1;
else
floppy_sizes[i] = MAX_DISK_SIZE;
floppy_blocksizes[i] = 512;
floppy_maxsectors[i] = 64;
}
blk_size[MAJOR_NR] = floppy_sizes;
blksize_size[MAJOR_NR] = floppy_blocksizes;
max_sectors[MAJOR_NR] = floppy_maxsectors;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
config_types();
for (i = 0; i < N_FDC; i++) {
fdc = i;
CLEARSTRUCT(FDCS);
FDCS->dtr = -1;
FDCS->dor = 0x4;
#if defined(__sparc__) || defined(__mc68000__)
#ifdef __mc68000__
if(MACH_IS_SUN3X)
#endif
FDCS->version = FDC_82072A;
#endif
}
use_virtual_dma = can_use_virtual_dma & 1;
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
devfs_unregister_blkdev(MAJOR_NR,"fd");
del_timer(&fd_timeout);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return -ENODEV;
}
#if N_FDC > 1
fdc_state[1].address = FDC2;
#endif
fdc = 0;
if (floppy_grab_irq_and_dma()){
del_timer(&fd_timeout);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
devfs_unregister_blkdev(MAJOR_NR,"fd");
return -EBUSY;
}
for (drive = 0; drive < N_DRIVE; drive++) {
CLEARSTRUCT(UDRS);
CLEARSTRUCT(UDRWE);
USETF(FD_DISK_NEWCHANGE);
USETF(FD_DISK_CHANGED);
USETF(FD_VERIFY);
UDRS->fd_device = -1;
floppy_track_buffer = NULL;
max_buffer_sectors = 0;
}
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/100 + 1);
for (i = 0; i < N_FDC; i++) {
fdc = i;
FDCS->driver_version = FD_DRIVER_VERSION;
for (unit=0; unit<4; unit++)
FDCS->track[unit] = 0;
if (FDCS->address == -1)
continue;
FDCS->rawcmd = 2;
if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){
release_region(FDCS->address+2, 4);
release_region(FDCS->address+7, 1);
FDCS->address = -1;
FDCS->version = FDC_NONE;
continue;
}
FDCS->version = get_fdc_version();
if (FDCS->version == FDC_NONE){
release_region(FDCS->address+2, 4);
release_region(FDCS->address+7, 1);
FDCS->address = -1;
continue;
}
if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
can_use_virtual_dma = 0;
have_no_fdc = 0;
user_reset_fdc(-1,FD_RESET_ALWAYS,0);
}
fdc=0;
del_timer(&fd_timeout);
current_drive = 0;
floppy_release_irq_and_dma();
initialising=0;
if (have_no_fdc)
{
DPRINT("no floppy controllers found\n");
run_task_queue(&tq_immediate);
if (usage_count)
floppy_release_irq_and_dma();
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
devfs_unregister_blkdev(MAJOR_NR,"fd");
}
for (drive = 0; drive < N_DRIVE; drive++) {
motor_off_timer[drive].data = drive;
motor_off_timer[drive].function = motor_off_callback;
if (!(allowed_drive_mask & (1 << drive)))
continue;
if (fdc_state[FDC(drive)].version == FDC_NONE)
continue;
for (i = 0; i<NUMBER(floppy_type); i++)
register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4),
1, &floppy_fops, 0);
}
return have_no_fdc;
}
static int floppy_grab_irq_and_dma(void)
static void floppy_release_irq_and_dma(void)
static void __init parse_floppy_cfg_string(char *cfg)
int init_module(void)
void cleanup_module(void)