📄 amiflop.c
字号:
#ifdef DEBUG printk("access to track %d, sector %d, with buffer at " "0x%08lx\n", track, sector, data);#endif if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) { printk(KERN_WARNING "do_fd_request: unknown command\n"); end_request(0); goto repeat; } if (get_track(drive, track) == -1) { end_request(0); goto repeat; } switch (CURRENT->cmd) { case READ: memcpy(data, unit[drive].trackbuf + sector * 512, 512); break; case WRITE: memcpy(unit[drive].trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ if (!fd_motor_on(drive)) { end_request(0); goto repeat; } /* * setup a callback to write the track buffer * after a short (1 tick) delay. */ save_flags (flags); cli(); unit[drive].dirty = 1; /* reset the timer */ del_timer (flush_track_timer + drive); flush_track_timer[drive].expires = jiffies + 1; add_timer (flush_track_timer + drive); restore_flags (flags); break; } } CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; end_request(1); goto repeat;}static void do_fd_request(request_queue_t * q){ redo_fd_request();}static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param){ int drive = inode->i_rdev & 3; static struct floppy_struct getprm; struct super_block * sb; switch(cmd){ case HDIO_GETGEO: { struct hd_geometry loc; loc.heads = unit[drive].type->heads; loc.sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; loc.cylinders = unit[drive].type->tracks; loc.start = 0; if (copy_to_user((void *)param, (void *)&loc, sizeof(struct hd_geometry))) return -EFAULT; break; } case FDFMTBEG: get_fdc(drive); if (fd_ref[drive] > 1) { rel_fdc(); return -EBUSY; } fsync_dev(inode->i_rdev); if (fd_motor_on(drive) == 0) { rel_fdc(); return -ENODEV; } if (fd_calibrate(drive) == 0) { rel_fdc(); return -ENXIO; } floppy_off(drive); rel_fdc(); break; case FDFMTTRK: if (param < unit[drive].type->tracks * unit[drive].type->heads) { get_fdc(drive); if (fd_seek(drive,param) != 0){ memset(unit[drive].trackbuf, FD_FILL_BYTE, unit[drive].dtype->sects * unit[drive].type->sect_mult * 512); non_int_flush_track(drive); } floppy_off(drive); rel_fdc(); } else return -EINVAL; break; case FDFMTEND: floppy_off(drive); invalidate_device(inode->i_rdev, 0); break; case FDGETPRM: memset((void *)&getprm, 0, sizeof (getprm)); getprm.track=unit[drive].type->tracks; getprm.head=unit[drive].type->heads; getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult; getprm.size=unit[drive].blocks; if (copy_to_user((void *)param, (void *)&getprm, sizeof(struct floppy_struct))) return -EFAULT; break; case BLKGETSIZE: return put_user(unit[drive].blocks,(unsigned long *)param); break; case BLKGETSIZE64: return put_user((u64)unit[drive].blocks << 9, (u64 *)param); break; case FDSETPRM: case FDDEFPRM: return -EINVAL; case FDFLUSH: /* unconditionally, even if not needed */ del_timer (flush_track_timer + drive); non_int_flush_track(drive); break;#ifdef RAW_IOCTL case IOCTL_RAW_TRACK: if (copy_to_user((void *)param, raw_buf, unit[drive].type->read_size)) return -EFAULT; else return unit[drive].type->read_size;#endif default: printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.", cmd, drive); return -ENOSYS; } return 0;}static void fd_probe(int dev){ unsigned long code; int type; int drive; drive = dev & 3; code = fd_get_drive_id(drive); /* get drive type */ for (type = 0; type < num_dr_types; type++) if (drive_types[type].code == code) break; if (type >= num_dr_types) { printk(KERN_WARNING "fd_probe: unsupported drive type " "%08lx found\n", code); unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */ return; } unit[drive].type = drive_types + type; unit[drive].track = -1; unit[drive].disk = -1; unit[drive].motor = 0; unit[drive].busy = 0; unit[drive].status = -1;}/* * 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; int old_dev; int system; unsigned long flags; drive = MINOR(inode->i_rdev) & 3; old_dev = fd_device[drive]; if (fd_ref[drive]) if (old_dev != inode->i_rdev) return -EBUSY; if (unit[drive].type->code == FD_NODRIVE) return -ENODEV; if (filp && filp->f_mode & 3) { check_disk_change(inode->i_rdev); if (filp->f_mode & 2 ) { int wrprot; get_fdc(drive); fd_select (drive); wrprot = !(ciaa.pra & DSKPROT); fd_deselect (drive); rel_fdc(); if (wrprot) return -EROFS; } } save_flags(flags); cli(); fd_ref[drive]++; fd_device[drive] = inode->i_rdev;#ifdef MODULE if (unit[drive].motor == 0) MOD_INC_USE_COUNT;#endif restore_flags(flags); if (old_dev && old_dev != inode->i_rdev) invalidate_buffers(old_dev); system=(inode->i_rdev & 4)>>2; unit[drive].dtype=&data_types[system]; unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* data_types[system].sects*unit[drive].type->sect_mult; floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1; printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive, unit[drive].type->name, data_types[system].name); return 0;}static int floppy_release(struct inode * inode, struct file * filp){#ifdef DEBUG struct super_block * sb;#endif int drive = MINOR(inode->i_rdev) & 3; if (unit[drive].dirty == 1) { del_timer (flush_track_timer + drive); non_int_flush_track (drive); } if (!fd_ref[drive]--) { printk(KERN_CRIT "floppy_release with fd_ref == 0"); fd_ref[drive] = 0; }#ifdef MODULE/* the mod_use counter is handled this way */ floppy_off (drive | 0x40000000);#endif return 0;}/* * floppy-change is never called from an interrupt, so we can relax a bit * here, sleep etc. Note that floppy-on tries to set current_DOR to point * to the desired drive, but it will probably not survive the sleep if * several floppies are used at the same time: thus the loop. */static int amiga_floppy_change(kdev_t dev){ int drive = MINOR(dev) & 3; int changed; static int first_time = 1; if (MAJOR(dev) != MAJOR_NR) { printk(KERN_CRIT "floppy_change: not a floppy\n"); return 0; } if (first_time) changed = first_time--; else { get_fdc(drive); fd_select (drive); changed = !(ciaa.pra & DSKCHANGE); fd_deselect (drive); rel_fdc(); } if (changed) { fd_probe(drive); unit[drive].track = -1; unit[drive].dirty = 0; writepending = 0; /* if this was true before, too bad! */ writefromint = 0; return 1; } return 0;}static struct block_device_operations floppy_fops = { owner: THIS_MODULE, open: floppy_open, release: floppy_release, ioctl: fd_ioctl, check_media_change: amiga_floppy_change,};void __init amiga_floppy_setup (char *str, int *ints){ printk (KERN_INFO "amiflop: Setting default df0 to %x\n", ints[1]); fd_def_df0 = ints[1];}static int __init fd_probe_drives(void){ int drive,drives,nomem; printk(KERN_INFO "FD: probing units\n" KERN_INFO "found "); drives=0; nomem=0; for(drive=0;drive<FD_MAX_UNITS;drive++) { fd_probe(drive); if (unit[drive].type->code != FD_NODRIVE) { drives++; if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { printk("no mem for "); unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ drives--; nomem = 1; } printk("fd%d ",drive); } } if ((drives > 0) || (nomem == 0)) { if (drives == 0) printk("no drives"); printk("\n"); return drives; } printk("\n"); return -ENOMEM;}int __init amiga_floppy_init(void){ int i; if (!AMIGAHW_PRESENT(AMI_FLOPPY)) return -ENXIO; if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk("fd: Unable to get major %d for floppy\n",MAJOR_NR); return -EBUSY; } /* * We request DSKPTR, DSKLEN and DSKDATA only, because the other * floppy registers are too spreaded over the custom register space */ if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) { printk("fd: cannot get floppy registers\n"); unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) == NULL) { printk("fd: cannot get chip mem buffer\n"); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -ENOMEM; } if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) { printk("fd: cannot get irq for dma\n"); amiga_chip_free(raw_buf); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) { printk("fd: cannot get irq for timer\n"); free_irq(IRQ_AMIGA_DSKBLK, NULL); amiga_chip_free(raw_buf); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -EBUSY; } if (fd_probe_drives() < 1) { /* No usable drives */ free_irq(IRQ_AMIGA_CIAA_TB, NULL); free_irq(IRQ_AMIGA_DSKBLK, NULL); amiga_chip_free(raw_buf); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR,"fd"); return -ENXIO; } /* initialize variables */ init_timer(&motor_on_timer); motor_on_timer.expires = 0; motor_on_timer.data = 0; motor_on_timer.function = motor_on_callback; for (i = 0; i < FD_MAX_UNITS; i++) { init_timer(&motor_off_timer[i]); motor_off_timer[i].expires = 0; motor_off_timer[i].data = i|0x80000000; motor_off_timer[i].function = fd_motor_off; init_timer(&flush_track_timer[i]); flush_track_timer[i].expires = 0; flush_track_timer[i].data = i; flush_track_timer[i].function = flush_track_callback; unit[i].track = -1; } init_timer(&post_write_timer); post_write_timer.expires = 0; post_write_timer.data = 0; post_write_timer.function = post_write; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; for (i = 0; i < 128; i++) mfmdecode[i]=255; for (i = 0; i < 16; i++) mfmdecode[mfmencode[i]]=i; /* make sure that disk DMA is enabled */ custom.dmacon = DMAF_SETCLR | DMAF_DISK; /* init ms timer */ ciaa.crb = 8; /* one-shot, stop */ (void)do_floppy; /* avoid warning about unused variable */ return 0;}#ifdef MODULE#include <linux/version.h>int init_module(void){ if (!MACH_IS_AMIGA) return -ENXIO; return amiga_floppy_init();}void cleanup_module(void){ int i; for( i = 0; i < FD_MAX_UNITS; i++) if (unit[i].type->code != FD_NODRIVE) kfree(unit[i].trackbuf); free_irq(IRQ_AMIGA_CIAA_TB, NULL); free_irq(IRQ_AMIGA_DSKBLK, NULL); custom.dmacon = DMAF_DISK; /* disable DMA */ amiga_chip_free(raw_buf); blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); release_mem_region(CUSTOM_PHYSADDR+0x20, 8); unregister_blkdev(MAJOR_NR, "fd");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -