📄 ataflop.c
字号:
if (minor2disktype[type].drive_types > DriveType) return -ENODEV; type = minor2disktype[type].index; dtp = &disk_type[type]; if (UD.flags & FTD_MSG) printk (KERN_ERR "floppy%d: found dtp %p name %s!\n", drive, dtp, dtp->name); } else { if (!UDT) return -ENXIO; else dtp = UDT; } memset((void *)&getprm, 0, sizeof(getprm)); getprm.size = dtp->blocks; getprm.sect = dtp->spt; getprm.head = 2; getprm.track = dtp->blocks/dtp->spt/2; getprm.stretch = dtp->stretch; if (copy_to_user((void *)param, &getprm, sizeof(getprm))) return -EFAULT; return 0; } switch (cmd) { case FDSETPRM: case FDDEFPRM: /* * MSch 7/96: simple 'set geometry' case: just set the * 'default' device params (minor == 0). * Currently, the drive geometry is cleared after each * disk change and subsequent revalidate()! simple * implementation of FDDEFPRM: save geometry from a * FDDEFPRM call and restore it in floppy_revalidate() ! */ /* get the parameters from user space */ if (floppy->ref != 1 && floppy->ref != -1) return -EBUSY; if (copy_from_user(&setprm, (void *) param, sizeof(setprm))) return -EFAULT; /* * first of all: check for floppy change and revalidate, * or the next access will revalidate - and clear UDT :-( */ if (check_floppy_change(disk)) floppy_revalidate(disk); if (UD.flags & FTD_MSG) printk (KERN_INFO "floppy%d: setting size %d spt %d str %d!\n", drive, setprm.size, setprm.sect, setprm.stretch); /* what if type > 0 here? Overwrite specified entry ? */ if (type) { /* refuse to re-set a predefined type for now */ redo_fd_request(); return -EINVAL; } /* * type == 0: first look for a matching entry in the type list, * and set the UD.disktype field to use the perdefined entry. * TODO: add user-defined format to head of autoprobe list ? * Useful to include the user-type for future autodetection! */ for (settype = 0; settype < NUM_DISK_MINORS; settype++) { int setidx = 0; if (minor2disktype[settype].drive_types > DriveType) { /* skip this one, invalid for drive ... */ continue; } setidx = minor2disktype[settype].index; dtp = &disk_type[setidx]; /* found matching entry ?? */ if ( dtp->blocks == setprm.size && dtp->spt == setprm.sect && dtp->stretch == setprm.stretch ) { if (UD.flags & FTD_MSG) printk (KERN_INFO "floppy%d: setting %s %p!\n", drive, dtp->name, dtp); UDT = dtp; set_capacity(floppy->disk, UDT->blocks); if (cmd == FDDEFPRM) { /* save settings as permanent default type */ default_params[drive].name = dtp->name; default_params[drive].spt = dtp->spt; default_params[drive].blocks = dtp->blocks; default_params[drive].fdc_speed = dtp->fdc_speed; default_params[drive].stretch = dtp->stretch; } return 0; } } /* no matching disk type found above - setting user_params */ if (cmd == FDDEFPRM) { /* set permanent type */ dtp = &default_params[drive]; } else /* set user type (reset by disk change!) */ dtp = &user_params[drive]; dtp->name = "user format"; dtp->blocks = setprm.size; dtp->spt = setprm.sect; if (setprm.sect > 14) dtp->fdc_speed = 3; else dtp->fdc_speed = 0; dtp->stretch = setprm.stretch; if (UD.flags & FTD_MSG) printk (KERN_INFO "floppy%d: blk %d spt %d str %d!\n", drive, dtp->blocks, dtp->spt, dtp->stretch); /* sanity check */ if (!dtp || setprm.track != dtp->blocks/dtp->spt/2 || setprm.head != 2) { redo_fd_request(); return -EINVAL; } UDT = dtp; set_capacity(floppy->disk, UDT->blocks); return 0; case FDMSGON: UD.flags |= FTD_MSG; return 0; case FDMSGOFF: UD.flags &= ~FTD_MSG; return 0; case FDSETEMSGTRESH: return -EINVAL; case FDFMTBEG: return 0; case FDFMTTRK: if (floppy->ref != 1 && floppy->ref != -1) return -EBUSY; if (copy_from_user(&fmt_desc, (void *) param, sizeof(fmt_desc))) return -EFAULT; return do_format(drive, type, &fmt_desc); case FDCLRPRM: UDT = NULL; /* MSch: invalidate default_params */ default_params[drive].blocks = 0; set_capacity(floppy->disk, MAX_DISK_SIZE * 2); case FDFMTEND: case FDFLUSH: /* invalidate the buffer track to force a reread */ BufferDrive = -1; set_bit(drive, &fake_change); check_disk_change(inode->i_bdev); return 0; default: return -EINVAL; }}/* Initialize the 'unit' variable for drive 'drive' */static void __init fd_probe( int drive ){ UD.connected = 0; UDT = NULL; if (!fd_test_drive_present( drive )) return; UD.connected = 1; UD.track = 0; switch( UserSteprate[drive] ) { case 2: UD.steprate = FDCSTEP_2; break; case 3: UD.steprate = FDCSTEP_3; break; case 6: UD.steprate = FDCSTEP_6; break; case 12: UD.steprate = FDCSTEP_12; break; default: /* should be -1 for "not set by user" */ if (ATARIHW_PRESENT( FDCSPEED ) || MACH_IS_MEDUSA) UD.steprate = FDCSTEP_3; else UD.steprate = FDCSTEP_6; break; } MotorOn = 1; /* from probe restore operation! */}/* This function tests the physical presence of a floppy drive (not * whether a disk is inserted). This is done by issuing a restore * command, waiting max. 2 seconds (that should be enough to move the * head across the whole disk) and looking at the state of the "TR00" * signal. This should now be raised if there is a drive connected * (and there is no hardware failure :-) Otherwise, the drive is * declared absent. */static int __init fd_test_drive_present( int drive ){ unsigned long timeout; unsigned char status; int ok; if (drive >= (MACH_IS_FALCON ? 1 : 2)) return( 0 ); fd_select_drive( drive ); /* disable interrupt temporarily */ atari_turnoff_irq( IRQ_MFP_FDC ); FDC_WRITE (FDCREG_TRACK, 0xff00); FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 ); timeout = jiffies + 2*HZ+HZ/2; while (time_before(jiffies, timeout)) if (!(mfp.par_dt_reg & 0x20)) break; status = FDC_READ( FDCREG_STATUS ); ok = (status & FDCSTAT_TR00) != 0; /* force interrupt to abort restore operation (FDC would try * about 50 seconds!) */ FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); udelay(500); status = FDC_READ( FDCREG_STATUS ); udelay(20); if (ok) { /* dummy seek command to make WP bit accessible */ FDC_WRITE( FDCREG_DATA, 0 ); FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK ); while( mfp.par_dt_reg & 0x20 ) ; status = FDC_READ( FDCREG_STATUS ); } atari_turnon_irq( IRQ_MFP_FDC ); return( ok );}/* Look how many and which kind of drives are connected. If there are * floppies, additionally start the disk-change and motor-off timers. */static void __init config_types( void ){ int drive, cnt = 0; /* for probing drives, set the FDC speed to 8 MHz */ if (ATARIHW_PRESENT(FDCSPEED)) dma_wd.fdc_speed = 0; printk(KERN_INFO "Probing floppy drive(s):\n"); for( drive = 0; drive < FD_MAX_UNITS; drive++ ) { fd_probe( drive ); if (UD.connected) { printk(KERN_INFO "fd%d\n", drive); ++cnt; } } if (FDC_READ( FDCREG_STATUS ) & FDCSTAT_BUSY) { /* If FDC is still busy from probing, give it another FORCI * command to abort the operation. If this isn't done, the FDC * will interrupt later and its IRQ line stays low, because * the status register isn't read. And this will block any * interrupts on this IRQ line :-( */ FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); udelay(500); FDC_READ( FDCREG_STATUS ); udelay(20); } if (cnt > 0) { start_motor_off_timer(); if (cnt == 1) fd_select_drive( 0 ); start_check_change_timer(); }}/* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */static int floppy_open( struct inode *inode, struct file *filp ){ struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data; int type = iminor(inode) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (p->ref && p->type != type) return -EBUSY; if (p->ref == -1 || (p->ref && filp->f_flags & O_EXCL)) return -EBUSY; if (filp->f_flags & O_EXCL) p->ref = -1; else p->ref++; p->type = type; if (filp->f_flags & O_NDELAY) return 0; if (filp->f_mode & 3) { check_disk_change(inode->i_bdev); if (filp->f_mode & 2) { if (p->wpstat) { if (p->ref < 0) p->ref = 0; else p->ref--; floppy_release(inode, filp); return -EROFS; } } } return 0;}static int floppy_release( struct inode * inode, struct file * filp ){ struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data; if (p->ref < 0) p->ref = 0; else if (!p->ref--) { printk(KERN_ERR "floppy_release with fd_ref == 0"); p->ref = 0; } return 0;}static struct block_device_operations floppy_fops = { .owner = THIS_MODULE, .open = floppy_open, .release = floppy_release, .ioctl = fd_ioctl, .media_changed = check_floppy_change, .revalidate_disk= floppy_revalidate,};static struct kobject *floppy_find(dev_t dev, int *part, void *data){ int drive = *part & 3; int type = *part >> 2; if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return NULL; *part = 0; return get_disk(unit[drive].disk);}static int __init atari_floppy_init (void){ int i; if (!MACH_IS_ATARI) /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ return -ENXIO; if (MACH_IS_HADES) /* Hades doesn't have Atari-compatible floppy */ return -ENXIO; if (register_blkdev(FLOPPY_MAJOR,"fd")) return -EBUSY; for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].disk = alloc_disk(1); if (!unit[i].disk) goto Enomem; } if (UseTrackbuffer < 0) /* not set by user -> use default: for now, we turn track buffering off for all Medusas, though it could be used with ones that have a counter card. But the test is too hard :-( */ UseTrackbuffer = !MACH_IS_MEDUSA; /* initialize variables */ SelectedDrive = -1; BufferDrive = -1; DMABuffer = atari_stram_alloc(BUFFER_SIZE+512, "ataflop"); if (!DMABuffer) { printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n"); goto Enomem; } TrackBuffer = DMABuffer + 512; PhysDMABuffer = virt_to_phys(DMABuffer); PhysTrackBuffer = virt_to_phys(TrackBuffer); BufferDrive = BufferSide = BufferTrack = -1; floppy_queue = blk_init_queue(do_fd_request, &ataflop_lock); if (!floppy_queue) goto Enomem; for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; unit[i].flags = 0; unit[i].disk->major = FLOPPY_MAJOR; unit[i].disk->first_minor = i; sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; unit[i].disk->private_data = &unit[i]; unit[i].disk->queue = floppy_queue; set_capacity(unit[i].disk, MAX_DISK_SIZE * 2); add_disk(unit[i].disk); } blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE, floppy_find, NULL, NULL); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', UseTrackbuffer ? "" : "no "); config_types(); return 0;Enomem: while (i--) put_disk(unit[i].disk); if (floppy_queue) blk_cleanup_queue(floppy_queue); unregister_blkdev(FLOPPY_MAJOR, "fd"); return -ENOMEM;}void __init atari_floppy_setup( char *str, int *ints ){ int i; if (ints[0] < 1) { printk(KERN_ERR "ataflop_setup: no arguments!\n" ); return; } else if (ints[0] > 2+FD_MAX_UNITS) { printk(KERN_ERR "ataflop_setup: too many arguments\n" ); } if (ints[1] < 0 || ints[1] > 2) printk(KERN_ERR "ataflop_setup: bad drive type\n" ); else DriveType = ints[1]; if (ints[0] >= 2) UseTrackbuffer = (ints[2] > 0); for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) { if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12) printk(KERN_ERR "ataflop_setup: bad steprate\n" ); else UserSteprate[i-3] = ints[i]; }}static void atari_floppy_exit(void){ int i; blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); for (i = 0; i < FD_MAX_UNITS; i++) { del_gendisk(unit[i].disk); put_disk(unit[i].disk); } unregister_blkdev(FLOPPY_MAJOR, "fd"); blk_cleanup_queue(floppy_queue); del_timer_sync(&fd_timer); atari_stram_free( DMABuffer );}module_init(atari_floppy_init)module_exit(atari_floppy_exit)MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -