⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amiflop.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		case READ:			memcpy(data, floppy->trackbuf + sector * 512, 512);			break;		case WRITE:			memcpy(floppy->trackbuf + sector * 512, data, 512);			/* keep the drive spinning while writes are scheduled */			if (!fd_motor_on(drive)) {				end_request(CURRENT, 0);				goto repeat;			}			/*			 * setup a callback to write the track buffer			 * after a short (1 tick) delay.			 */			local_irq_save(flags);			floppy->dirty = 1;		        /* reset the timer */			mod_timer (flush_track_timer + drive, jiffies + 1);			local_irq_restore(flags);			break;		}	}	CURRENT->nr_sectors -= CURRENT->current_nr_sectors;	CURRENT->sector += CURRENT->current_nr_sectors;	end_request(CURRENT, 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 = iminor(inode) & 3;	static struct floppy_struct getprm;	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_bdev(inode->i_bdev);		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_bdev(inode->i_bdev, 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 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 = iminor(inode) & 3;	int system =  (iminor(inode) & 4) >> 2;	int old_dev;	unsigned long flags;	old_dev = fd_device[drive];	if (fd_ref[drive] && old_dev != system)		return -EBUSY;	if (filp && filp->f_mode & 3) {		check_disk_change(inode->i_bdev);		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;		}	}	local_irq_save(flags);	fd_ref[drive]++;	fd_device[drive] = system;	local_irq_restore(flags);	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;	set_capacity(unit[drive].gendisk, unit[drive].blocks);	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){	int drive = iminor(inode) & 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(struct gendisk *disk){	struct amiga_floppy_struct *p = disk->private_data;	int drive = p - unit;	int changed;	static int first_time = 1;	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);		p->track = -1;		p->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,	.media_changed	= 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++) {		struct gendisk *disk;		fd_probe(drive);		if (unit[drive].type->code == FD_NODRIVE)			continue;		disk = alloc_disk(1);		if (!disk) {			unit[drive].type->code = FD_NODRIVE;			continue;		}		unit[drive].gendisk = disk;		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);		disk->major = FLOPPY_MAJOR;		disk->first_minor = drive;		disk->fops = &floppy_fops;		sprintf(disk->disk_name, "fd%d", drive);		disk->private_data = &unit[drive];		disk->queue = floppy_queue;		set_capacity(disk, 880*2);		add_disk(disk);	}	if ((drives > 0) || (nomem == 0)) {		if (drives == 0)			printk("no drives");		printk("\n");		return drives;	}	printk("\n");	return -ENOMEM;} static struct kobject *floppy_find(dev_t dev, int *part, void *data){	int drive = *part & 3;	if (unit[drive].type->code == FD_NODRIVE)		return NULL;	*part = 0;	return get_disk(unit[drive].gendisk);}int __init amiga_floppy_init(void){	int i, ret;	if (!AMIGAHW_PRESENT(AMI_FLOPPY))		return -ENXIO;	if (register_blkdev(FLOPPY_MAJOR,"fd"))		return -EBUSY;	/*	 *  We request DSKPTR, DSKLEN and DSKDATA only, because the other	 *  floppy registers are too spreaded over the custom register space	 */	ret = -EBUSY;	if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) {		printk("fd: cannot get floppy registers\n");		goto out_blkdev;	}	ret = -ENOMEM;	if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) ==	    NULL) {		printk("fd: cannot get chip mem buffer\n");		goto out_memregion;	}	ret = -EBUSY;	if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) {		printk("fd: cannot get irq for dma\n");		goto out_irq;	}	if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) {		printk("fd: cannot get irq for timer\n");		goto out_irq2;	}	ret = -ENOMEM;	floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock);	if (!floppy_queue)		goto out_queue;	ret = -ENXIO;	if (fd_probe_drives() < 1) /* No usable drives */		goto out_probe;	blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,				floppy_find, NULL, NULL);	/* 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;  	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 */	return 0;out_probe:	blk_cleanup_queue(floppy_queue);out_queue:	free_irq(IRQ_AMIGA_CIAA_TB, NULL);out_irq2:	free_irq(IRQ_AMIGA_DSKBLK, NULL);out_irq:	amiga_chip_free(raw_buf);out_memregion:	release_mem_region(CUSTOM_PHYSADDR+0x20, 8);out_blkdev:	unregister_blkdev(FLOPPY_MAJOR,"fd");	return ret;}#ifdef MODULE#include <linux/version.h>int init_module(void){	if (!MACH_IS_AMIGA)		return -ENXIO;	return amiga_floppy_init();}#if 0 /* not safe to unload */void cleanup_module(void){	int i;	for( i = 0; i < FD_MAX_UNITS; i++) {		if (unit[i].type->code != FD_NODRIVE) {			del_gendisk(unit[i].gendisk);			put_disk(unit[i].gendisk);			kfree(unit[i].trackbuf);		}	}	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);	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_cleanup_queue(floppy_queue);	release_mem_region(CUSTOM_PHYSADDR+0x20, 8);	unregister_blkdev(FLOPPY_MAJOR, "fd");}#endif#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -