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

📄 viocd.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,			HvLpEvent_Type_VirtualIo,			viomajorsubtype_cdio | viocdlockdoor,			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,			viopath_sourceinst(viopath_hostLp),			viopath_targetinst(viopath_hostLp),			(u64)&we, VIOVERSION << 16,			(device_no << 48) | (flags << 32), 0, 0, 0);	if (hvrc != 0) {		printk(VIOCD_KERN_WARNING "bad rc on HvCallEvent_signalLpEventFast %d\n",				(int)hvrc);		return -EIO;	}	wait_for_completion(&we.com);	if (we.rc != 0)		return -EIO;	return 0;}static int viocd_packet(struct cdrom_device_info *cdi,		struct packet_command *cgc){	unsigned int buflen = cgc->buflen;	int ret = -EIO;	switch (cgc->cmd[0]) {	case GPCMD_READ_DISC_INFO:		{			disc_information *di = (disc_information *)cgc->buffer;			if (buflen >= 2) {				di->disc_information_length = cpu_to_be16(1);				ret = 0;			}			if (buflen >= 3)				di->erasable =					(cdi->ops->capability & ~cdi->mask					 & (CDC_DVD_RAM | CDC_RAM)) != 0;		}		break;	case GPCMD_GET_CONFIGURATION:		if (cgc->cmd[3] == CDF_RWRT) {			struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));			if ((buflen >=			     (sizeof(struct feature_header) + sizeof(*rfd))) &&			    (cdi->ops->capability & ~cdi->mask			     & (CDC_DVD_RAM | CDC_RAM))) {				rfd->feature_code = cpu_to_be16(CDF_RWRT);				rfd->curr = 1;				ret = 0;			}		}		break;	default:		if (cgc->sense) {			/* indicate Unknown code */			cgc->sense->sense_key = 0x05;			cgc->sense->asc = 0x20;			cgc->sense->ascq = 0x00;		}		break;	}	cgc->stat = ret;	return ret;}static void restart_all_queues(int first_index){	int i;	for (i = first_index + 1; i < viocd_numdev; i++)		if (viocd_diskinfo[i].viocd_disk)			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);	for (i = 0; i <= first_index; i++)		if (viocd_diskinfo[i].viocd_disk)			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);}/* This routine handles incoming CD LP events */static void vio_handle_cd_event(struct HvLpEvent *event){	struct viocdlpevent *bevent;	struct viocd_waitevent *pwe;	struct disk_info *di;	unsigned long flags;	struct request *req;	if (event == NULL)		/* Notification that a partition went away! */		return;	/* First, we should NEVER get an int here...only acks */	if (hvlpevent_is_int(event)) {		printk(VIOCD_KERN_WARNING				"Yikes! got an int in viocd event handler!\n");		if (hvlpevent_need_ack(event)) {			event->xRc = HvLpEvent_Rc_InvalidSubtype;			HvCallEvent_ackLpEvent(event);		}	}	bevent = (struct viocdlpevent *)event;	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {	case viocdopen:		if (event->xRc == 0) {			di = &viocd_diskinfo[bevent->disk];			blk_queue_hardsect_size(di->viocd_disk->queue,					bevent->block_size);			set_capacity(di->viocd_disk,					bevent->media_size *					bevent->block_size / 512);		}		/* FALLTHROUGH !! */	case viocdlockdoor:		pwe = (struct viocd_waitevent *)event->xCorrelationToken;return_complete:		pwe->rc = event->xRc;		pwe->sub_result = bevent->sub_result;		complete(&pwe->com);		break;	case viocdcheck:		pwe = (struct viocd_waitevent *)event->xCorrelationToken;		pwe->changed = bevent->flags;		goto return_complete;	case viocdclose:		break;	case viocdwrite:	case viocdread:		/*		 * Since this is running in interrupt mode, we need to		 * make sure we're not stepping on any global I/O operations		 */		di = &viocd_diskinfo[bevent->disk];		spin_lock_irqsave(&viocd_reqlock, flags);		dma_unmap_single(di->dev, bevent->token, bevent->len,				((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread)				?  DMA_FROM_DEVICE : DMA_TO_DEVICE);		req = (struct request *)bevent->event.xCorrelationToken;		rwreq--;		if (event->xRc != HvLpEvent_Rc_Good) {			const struct vio_error_entry *err =				vio_lookup_rc(viocd_err_table,						bevent->sub_result);			printk(VIOCD_KERN_WARNING "request %p failed "					"with rc %d:0x%04X: %s\n",					req, event->xRc,					bevent->sub_result, err->msg);			viocd_end_request(req, 0);		} else			viocd_end_request(req, 1);		/* restart handling of incoming requests */		spin_unlock_irqrestore(&viocd_reqlock, flags);		restart_all_queues(bevent->disk);		break;	default:		printk(VIOCD_KERN_WARNING				"message with invalid subtype %0x04X!\n",				event->xSubtype & VIOMINOR_SUBTYPE_MASK);		if (hvlpevent_need_ack(event)) {			event->xRc = HvLpEvent_Rc_InvalidSubtype;			HvCallEvent_ackLpEvent(event);		}	}}static struct cdrom_device_ops viocd_dops = {	.open = viocd_open,	.release = viocd_release,	.media_changed = viocd_media_changed,	.lock_door = viocd_lock_door,	.generic_packet = viocd_packet,	.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM};static int __init find_capability(const char *type){	struct capability_entry *entry;	for(entry = capability_table; entry->type; ++entry)		if(!strncmp(entry->type, type, 4))			break;	return entry->capability;}static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id){	struct gendisk *gendisk;	int deviceno;	struct disk_info *d;	struct cdrom_device_info *c;	struct request_queue *q;	struct device_node *node = vdev->dev.archdata.of_node;	deviceno = vdev->unit_address;	if (deviceno > VIOCD_MAX_CD)		return -ENODEV;	if (!node)		return -ENODEV;	if (deviceno >= viocd_numdev)		viocd_numdev = deviceno + 1;	d = &viocd_diskinfo[deviceno];	d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);	d->type = of_get_property(node, "linux,vio_type", NULL);	d->model = of_get_property(node, "linux,vio_model", NULL);	c = &d->viocd_info;	c->ops = &viocd_dops;	c->speed = 4;	c->capacity = 1;	c->handle = d;	c->mask = ~find_capability(d->type);	sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);	if (register_cdrom(c) != 0) {		printk(VIOCD_KERN_WARNING "Cannot register viocd CD-ROM %s!\n",				c->name);		goto out;	}	printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "			"type %4.4s, model %3.3s\n",			c->name, d->rsrcname, d->type, d->model);	q = blk_init_queue(do_viocd_request, &viocd_reqlock);	if (q == NULL) {		printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",				c->name);		goto out_unregister_cdrom;	}	gendisk = alloc_disk(1);	if (gendisk == NULL) {		printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n",				c->name);		goto out_cleanup_queue;	}	gendisk->major = VIOCD_MAJOR;	gendisk->first_minor = deviceno;	strncpy(gendisk->disk_name, c->name,			sizeof(gendisk->disk_name));	blk_queue_max_hw_segments(q, 1);	blk_queue_max_phys_segments(q, 1);	blk_queue_max_sectors(q, 4096 / 512);	gendisk->queue = q;	gendisk->fops = &viocd_fops;	gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;	set_capacity(gendisk, 0);	gendisk->private_data = d;	d->viocd_disk = gendisk;	d->dev = &vdev->dev;	gendisk->driverfs_dev = d->dev;	add_disk(gendisk);	return 0;out_cleanup_queue:	blk_cleanup_queue(q);out_unregister_cdrom:	unregister_cdrom(c);out:	return -ENODEV;}static int viocd_remove(struct vio_dev *vdev){	struct disk_info *d = &viocd_diskinfo[vdev->unit_address];	if (unregister_cdrom(&d->viocd_info) != 0)		printk(VIOCD_KERN_WARNING				"Cannot unregister viocd CD-ROM %s!\n",				d->viocd_info.name);	del_gendisk(d->viocd_disk);	blk_cleanup_queue(d->viocd_disk->queue);	put_disk(d->viocd_disk);	return 0;}/** * viocd_device_table: Used by vio.c to match devices that we * support. */static struct vio_device_id viocd_device_table[] __devinitdata = {	{ "block", "IBM,iSeries-viocd" },	{ "", "" }};MODULE_DEVICE_TABLE(vio, viocd_device_table);static struct vio_driver viocd_driver = {	.id_table = viocd_device_table,	.probe = viocd_probe,	.remove = viocd_remove,	.driver = {		.name = "viocd",		.owner = THIS_MODULE,	}};static int __init viocd_init(void){	struct proc_dir_entry *e;	int ret = 0;	if (!firmware_has_feature(FW_FEATURE_ISERIES))		return -ENODEV;	if (viopath_hostLp == HvLpIndexInvalid) {		vio_set_hostlp();		/* If we don't have a host, bail out */		if (viopath_hostLp == HvLpIndexInvalid)			return -ENODEV;	}	printk(VIOCD_KERN_INFO "vers " VIOCD_VERS ", hosting partition %d\n",			viopath_hostLp);	if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) {		printk(VIOCD_KERN_WARNING "Unable to get major %d for %s\n",				VIOCD_MAJOR, VIOCD_DEVICE);		return -EIO;	}	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio,			MAX_CD_REQ + 2);	if (ret) {		printk(VIOCD_KERN_WARNING				"error opening path to host partition %d\n",				viopath_hostLp);		goto out_unregister;	}	/* Initialize our request handler */	vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);	spin_lock_init(&viocd_reqlock);	ret = vio_register_driver(&viocd_driver);	if (ret)		goto out_free_info;	e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL);	if (e) {		e->owner = THIS_MODULE;		e->proc_fops = &proc_viocd_operations;	}	return 0;out_free_info:	vio_clearHandler(viomajorsubtype_cdio);	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);out_unregister:	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);	return ret;}static void __exit viocd_exit(void){	remove_proc_entry("iSeries/viocd", NULL);	vio_unregister_driver(&viocd_driver);	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);	vio_clearHandler(viomajorsubtype_cdio);	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);}module_init(viocd_init);module_exit(viocd_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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