📄 ataflop.c
字号:
{ int drive, type; kdev_t device; struct atari_format_descr fmt_desc; struct atari_disk_type *dtp; struct floppy_struct getprm; int settype; struct floppy_struct setprm; device = inode->i_rdev; switch (cmd) { case BLKROSET: case BLKROGET: case BLKRASET: case BLKRAGET: case BLKFLSBUF: return blk_ioctl(device, cmd, param); } drive = MINOR (device); type = drive >> 2; drive &= 3; switch (cmd) { case FDGETPRM: case BLKGETSIZE: if (type) { if (--type >= NUM_DISK_MINORS) return -ENODEV; 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; } if (cmd == BLKGETSIZE) return put_user(dtp->blocks, (unsigned long *)param); 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 (fd_ref[drive] != 1 && fd_ref[drive] != -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(device)) floppy_revalidate(device); 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; floppy_sizes[drive] = UDT->blocks >> 1; 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; floppy_sizes[drive] = UDT->blocks >> 1; 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 (fd_ref[drive] != 1 && fd_ref[drive] != -1) return -EBUSY; if (copy_from_user(&fmt_desc, (void *) param, sizeof(fmt_desc))) return -EFAULT; return do_format(device, &fmt_desc); case FDCLRPRM: UDT = NULL; /* MSch: invalidate default_params */ default_params[drive].blocks = 0; floppy_sizes[drive] = MAX_DISK_SIZE; return invalidate_drive (device); case FDFMTEND: case FDFLUSH: return invalidate_drive(device); } 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 ){ int drive, type; int old_dev; if (!filp) { DPRINT (("Weird, open called with filp=0\n")); return -EIO; } drive = MINOR(inode->i_rdev) & 3; type = MINOR(inode->i_rdev) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return -ENXIO; old_dev = fd_device[drive]; if (fd_ref[drive] && old_dev != MINOR(inode->i_rdev)) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) return -EBUSY; if (filp->f_flags & O_EXCL) fd_ref[drive] = -1; else fd_ref[drive]++; fd_device[drive] = MINOR(inode->i_rdev); if (old_dev && old_dev != MINOR(inode->i_rdev)) invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev)); if (filp->f_flags & O_NDELAY) return 0; if (filp->f_mode & 3) { check_disk_change(inode->i_rdev); if (filp->f_mode & 2) { if (UD.wpstat) { floppy_release(inode, filp); return -EROFS; } } } return 0;}static int floppy_release( struct inode * inode, struct file * filp ){ int drive = MINOR(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; else if (!fd_ref[drive]--) { printk(KERN_ERR "floppy_release with fd_ref == 0"); fd_ref[drive] = 0; } return 0;}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,};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(MAJOR_NR,"fd",&floppy_fops)) { printk(KERN_ERR "Unable to get major %d for floppy\n",MAJOR_NR); return -EBUSY; } 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"); unregister_blkdev(MAJOR_NR, "fd"); return -ENOMEM; } TrackBuffer = DMABuffer + 512; PhysDMABuffer = virt_to_phys(DMABuffer); PhysTrackBuffer = virt_to_phys(TrackBuffer); BufferDrive = BufferSide = BufferTrack = -1; for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; unit[i].flags = 0; } for (i = 0; i < 256; i++) if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_MINORS) { int type = minor2disktype[(i >> 2) - 1].index; floppy_sizes[i] = disk_type[type].blocks >> 1; } else floppy_sizes[i] = MAX_DISK_SIZE; blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', UseTrackbuffer ? "" : "no "); config_types(); (void)do_floppy; /* avoid warning about unused variable */ return 0;}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]; }}#ifdef MODULEMODULE_LICENSE("GPL");int init_module (void){ if (!MACH_IS_ATARI) return -ENXIO; return atari_floppy_init ();}void cleanup_module (void){ unregister_blkdev(MAJOR_NR, "fd"); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); del_timer_sync(&fd_timer); atari_stram_free( DMABuffer );}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -