viotape.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,130 行 · 第 1/2 页

C
1,130
字号
	op->count = count;	init_completion(&op->com);	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,			HvLpEvent_Type_VirtualIo,			viomajorsubtype_tape | viotaperead,			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,			viopath_sourceinst(viopath_hostLp),			viopath_targetinst(viopath_hostLp),			(u64)(unsigned long)op, VIOVERSION << 16,			((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);	if (hvrc != HvLpEvent_Rc_Good) {		printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n",				(int)hvrc);		ret = -EIO;		goto free_dma;	}	wait_for_completion(&op->com);	if (op->rc)		ret = tape_rc_to_errno(op->rc, "read", devi.devno);	else {		ret = op->count;		if (ret && copy_to_user(buf, op->buffer, ret)) {			printk(VIOTAPE_KERN_WARN "error on copy_to_user\n");			ret = -EFAULT;		}	}free_dma:	dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);up_sem:	up(&reqSem);free_op:	free_op_struct(op);	return ret;}/* ioctl */static int viotap_ioctl(struct inode *inode, struct file *file,		unsigned int cmd, unsigned long arg){	HvLpEvent_Rc hvrc;	int ret;	struct viot_devinfo_struct devi;	struct mtop mtc;	u32 myOp;	struct op_struct *op = get_op_struct();	if (op == NULL)		return -ENOMEM;	get_dev_info(file->f_dentry->d_inode, &devi);	down(&reqSem);	ret = -EINVAL;	switch (cmd) {	case MTIOCTOP:		ret = -EFAULT;		/*		 * inode is null if and only if we (the kernel)		 * made the request		 */		if (inode == NULL)			memcpy(&mtc, (void *) arg, sizeof(struct mtop));		else if (copy_from_user((char *)&mtc, (char *)arg,					sizeof(struct mtop)))			goto free_op;		ret = -EIO;		switch (mtc.mt_op) {		case MTRESET:			myOp = VIOTAPOP_RESET;			break;		case MTFSF:			myOp = VIOTAPOP_FSF;			break;		case MTBSF:			myOp = VIOTAPOP_BSF;			break;		case MTFSR:			myOp = VIOTAPOP_FSR;			break;		case MTBSR:			myOp = VIOTAPOP_BSR;			break;		case MTWEOF:			myOp = VIOTAPOP_WEOF;			break;		case MTREW:			myOp = VIOTAPOP_REW;			break;		case MTNOP:			myOp = VIOTAPOP_NOP;			break;		case MTEOM:			myOp = VIOTAPOP_EOM;			break;		case MTERASE:			myOp = VIOTAPOP_ERASE;			break;		case MTSETBLK:			myOp = VIOTAPOP_SETBLK;			break;		case MTSETDENSITY:			myOp = VIOTAPOP_SETDENSITY;			break;		case MTTELL:			myOp = VIOTAPOP_GETPOS;			break;		case MTSEEK:			myOp = VIOTAPOP_SETPOS;			break;		case MTSETPART:			myOp = VIOTAPOP_SETPART;			break;		case MTOFFL:			myOp = VIOTAPOP_UNLOAD;			break;		default:			printk(VIOTAPE_KERN_WARN "MTIOCTOP called "					"with invalid op 0x%x\n", mtc.mt_op);			goto free_op;		}		/*		 * if we moved the head, we are no longer		 * reading or writing		 */		switch (mtc.mt_op) {		case MTFSF:		case MTBSF:		case MTFSR:		case MTBSR:		case MTTELL:		case MTSEEK:		case MTREW:			chg_state(devi.devno, VIOT_IDLE, file);		}		init_completion(&op->com);		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,				HvLpEvent_Type_VirtualIo,				viomajorsubtype_tape | viotapeop,				HvLpEvent_AckInd_DoAck,				HvLpEvent_AckType_ImmediateAck,				viopath_sourceinst(viopath_hostLp),				viopath_targetinst(viopath_hostLp),				(u64)(unsigned long)op,				VIOVERSION << 16,				((u64)devi.devno << 48), 0,				(((u64)myOp) << 32) | mtc.mt_count, 0);		if (hvrc != HvLpEvent_Rc_Good) {			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",					(int)hvrc);			goto free_op;		}		wait_for_completion(&op->com);		ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno);		goto free_op;	case MTIOCGET:		ret = -EIO;		init_completion(&op->com);		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,				HvLpEvent_Type_VirtualIo,				viomajorsubtype_tape | viotapegetstatus,				HvLpEvent_AckInd_DoAck,				HvLpEvent_AckType_ImmediateAck,				viopath_sourceinst(viopath_hostLp),				viopath_targetinst(viopath_hostLp),				(u64)(unsigned long)op, VIOVERSION << 16,				((u64)devi.devno << 48), 0, 0, 0);		if (hvrc != HvLpEvent_Rc_Good) {			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",					(int)hvrc);			goto free_op;		}		wait_for_completion(&op->com);		/* Operation is complete - grab the error code */		ret = tape_rc_to_errno(op->rc, "get status", devi.devno);		free_op_struct(op);		up(&reqSem);		if ((ret == 0) && copy_to_user((void *)arg,					&viomtget[devi.devno],					sizeof(viomtget[0])))			ret = -EFAULT;		return ret;	case MTIOCPOS:		printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n");		break;	default:		printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n",				cmd);		break;	}free_op:	free_op_struct(op);	up(&reqSem);	return ret;}static int viotap_open(struct inode *inode, struct file *file){	HvLpEvent_Rc hvrc;	struct viot_devinfo_struct devi;	int ret;	struct op_struct *op = get_op_struct();	if (op == NULL)		return -ENOMEM;	get_dev_info(file->f_dentry->d_inode, &devi);	/* Note: We currently only support one mode! */	if ((devi.devno >= viotape_numdev) || (devi.mode)) {		ret = -ENODEV;		goto free_op;	}	init_completion(&op->com);	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,			HvLpEvent_Type_VirtualIo,			viomajorsubtype_tape | viotapeopen,			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,			viopath_sourceinst(viopath_hostLp),			viopath_targetinst(viopath_hostLp),			(u64)(unsigned long)op, VIOVERSION << 16,			((u64)devi.devno << 48), 0, 0, 0);	if (hvrc != 0) {		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",				(int) hvrc);		ret = -EIO;		goto free_op;	}	wait_for_completion(&op->com);	ret = tape_rc_to_errno(op->rc, "open", devi.devno);free_op:	free_op_struct(op);	return ret;}static int viotap_release(struct inode *inode, struct file *file){	HvLpEvent_Rc hvrc;	struct viot_devinfo_struct devi;	int ret = 0;	struct op_struct *op = get_op_struct();	if (op == NULL)		return -ENOMEM;	init_completion(&op->com);	get_dev_info(file->f_dentry->d_inode, &devi);	if (devi.devno >= viotape_numdev) {		ret = -ENODEV;		goto free_op;	}	chg_state(devi.devno, VIOT_IDLE, file);	if (devi.rewind) {		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,				HvLpEvent_Type_VirtualIo,				viomajorsubtype_tape | viotapeop,				HvLpEvent_AckInd_DoAck,				HvLpEvent_AckType_ImmediateAck,				viopath_sourceinst(viopath_hostLp),				viopath_targetinst(viopath_hostLp),				(u64)(unsigned long)op, VIOVERSION << 16,				((u64)devi.devno << 48), 0,				((u64)VIOTAPOP_REW) << 32, 0);		wait_for_completion(&op->com);		tape_rc_to_errno(op->rc, "rewind", devi.devno);	}	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,			HvLpEvent_Type_VirtualIo,			viomajorsubtype_tape | viotapeclose,			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,			viopath_sourceinst(viopath_hostLp),			viopath_targetinst(viopath_hostLp),			(u64)(unsigned long)op, VIOVERSION << 16,			((u64)devi.devno << 48), 0, 0, 0);	if (hvrc != 0) {		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",				(int) hvrc);		ret = -EIO;		goto free_op;	}	wait_for_completion(&op->com);	if (op->rc)		printk(VIOTAPE_KERN_WARN "close failed\n");free_op:	free_op_struct(op);	return ret;}struct file_operations viotap_fops = {	owner: THIS_MODULE,	read: viotap_read,	write: viotap_write,	ioctl: viotap_ioctl,	open: viotap_open,	release: viotap_release,};/* Handle interrupt events for tape */static void vioHandleTapeEvent(struct HvLpEvent *event){	int tapeminor;	struct op_struct *op;	struct viotapelpevent *tevent = (struct viotapelpevent *)event;	if (event == NULL) {		/* Notification that a partition went away! */		if (!viopath_isactive(viopath_hostLp)) {			/* TODO! Clean up */		}		return;	}	tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;	op = (struct op_struct *)event->xCorrelationToken;	switch (tapeminor) {	case viotapegetinfo:	case viotapeopen:	case viotapeclose:		op->rc = tevent->sub_type_result;		complete(&op->com);		break;	case viotaperead:		op->rc = tevent->sub_type_result;		op->count = tevent->len;		complete(&op->com);		break;	case viotapewrite:		if (op->non_blocking) {			dma_free_coherent(op->dev, op->count,					op->buffer, op->dmaaddr);			free_op_struct(op);			up(&reqSem);		} else {			op->rc = tevent->sub_type_result;			op->count = tevent->len;			complete(&op->com);		}		break;	case viotapeop:	case viotapegetpos:	case viotapesetpos:	case viotapegetstatus:		if (op) {			op->count = tevent->u.op.count;			op->rc = tevent->sub_type_result;			if (!op->non_blocking)				complete(&op->com);		}		break;	default:		printk(VIOTAPE_KERN_WARN "wierd ack\n");	}}static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id){	char tapename[32];	int i = vdev->unit_address;	int j;	if (i >= viotape_numdev)		return -ENODEV;	tape_device[i] = &vdev->dev;	state[i].cur_part = 0;	for (j = 0; j < MAX_PARTITIONS; ++j)		state[i].part_stat_rwi[j] = VIOT_IDLE;	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL,			"iseries!vt%d", i);	class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80),			NULL, "iseries!nvt%d", i);	devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR,			"iseries/vt%d", i);	devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),			S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i);	sprintf(tapename, "iseries/vt%d", i);	state[i].dev_handle = devfs_register_tape(tapename);	printk(VIOTAPE_KERN_INFO "tape %s is iSeries "			"resource %10.10s type %4.4s, model %3.3s\n",			tapename, viotape_unitinfo[i].rsrcname,			viotape_unitinfo[i].type, viotape_unitinfo[i].model);	return 0;}static int viotape_remove(struct vio_dev *vdev){	int i = vdev->unit_address;	devfs_remove("iseries/nvt%d", i);	devfs_remove("iseries/vt%d", i);	devfs_unregister_tape(state[i].dev_handle);	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80));	class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i));	return 0;}/** * viotape_device_table: Used by vio.c to match devices that we * support. */static struct vio_device_id viotape_device_table[] __devinitdata = {	{ "viotape", "" },	{ 0, }};MODULE_DEVICE_TABLE(vio, viotape_device_table);static struct vio_driver viotape_driver = {	.name = "viotape",	.id_table = viotape_device_table,	.probe = viotape_probe,	.remove = viotape_remove};int __init viotap_init(void){	int ret;	struct proc_dir_entry *e;	op_struct_list = NULL;	if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {		printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");		return ret;	}	spin_lock_init(&op_struct_list_lock);	sema_init(&reqSem, VIOTAPE_MAXREQ);	if (viopath_hostLp == HvLpIndexInvalid) {		vio_set_hostlp();		if (viopath_hostLp == HvLpIndexInvalid) {			ret = -ENODEV;			goto clear_op;		}	}	ret = viopath_open(viopath_hostLp, viomajorsubtype_tape,			VIOTAPE_MAXREQ + 2);	if (ret) {		printk(VIOTAPE_KERN_WARN				"error on viopath_open to hostlp %d\n", ret);		ret = -EIO;		goto clear_op;	}	printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION			", hosting partition %d\n", viopath_hostLp);	vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent);	ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops);	if (ret < 0) {		printk(VIOTAPE_KERN_WARN "Error registering viotape device\n");		goto clear_handler;	}	tape_class = class_simple_create(THIS_MODULE, "tape");	if (IS_ERR(tape_class)) {		printk(VIOTAPE_KERN_WARN "Unable to allocat class\n");		ret = PTR_ERR(tape_class);		goto unreg_chrdev;	}	if ((ret = get_viotape_info()) < 0) {		printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");		goto unreg_class;	}	ret = vio_register_driver(&viotape_driver);	if (ret)		goto unreg_class;	e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL);	if (e) {		e->owner = THIS_MODULE;		e->proc_fops = &proc_viotape_operations;	}	return 0;unreg_class:	class_simple_destroy(tape_class);unreg_chrdev:	unregister_chrdev(VIOTAPE_MAJOR, "viotape");clear_handler:	vio_clearHandler(viomajorsubtype_tape);	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);clear_op:	clear_op_struct_pool();	return ret;}/* Give a new state to the tape object */static int chg_state(int index, unsigned char new_state, struct file *file){	unsigned char *cur_state =	    &state[index].part_stat_rwi[state[index].cur_part];	int rc = 0;	/* if the same state, don't bother */	if (*cur_state == new_state)		return 0;	/* write an EOF if changing from writing to some other state */	if (*cur_state == VIOT_WRITING) {		struct mtop write_eof = { MTWEOF, 1 };		rc = viotap_ioctl(NULL, file, MTIOCTOP,				  (unsigned long)&write_eof);	}	*cur_state = new_state;	return rc;}/* Cleanup */static void __exit viotap_exit(void){	int ret;	remove_proc_entry("iSeries/viotape", NULL);	vio_unregister_driver(&viotape_driver);	class_simple_destroy(tape_class);	ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");	if (ret < 0)		printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",				ret);	if (viotape_unitinfo)		dma_free_coherent(iSeries_vio_dev,				sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,				viotape_unitinfo, viotape_unitinfo_token);	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);	vio_clearHandler(viomajorsubtype_tape);	clear_op_struct_pool();}MODULE_LICENSE("GPL");module_init(viotap_init);module_exit(viotap_exit);

⌨️ 快捷键说明

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