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

📄 optcd.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (status)		return status;	copy_from_user(&volctrl, (char *) arg, sizeof volctrl);	msf.cdmsf_min0 = 0x10;	msf.cdmsf_sec0 = 0x32;	msf.cdmsf_frame0 = volctrl.channel0;	msf.cdmsf_min1 = volctrl.channel1;	msf.cdmsf_sec1 = volctrl.channel2;	msf.cdmsf_frame1 = volctrl.channel3;	status = exec_long_cmd(COMCHCTRL, &msf);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));		return -EIO;	}	return 0;}static int cdromsubchnl(unsigned long arg){	int status;	struct cdrom_subchnl subchnl;	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);	if (status)		return status;	copy_from_user(&subchnl, (void *) arg, sizeof subchnl);	if (subchnl.cdsc_format != CDROM_LBA	    && subchnl.cdsc_format != CDROM_MSF)		return -EINVAL;	status = get_q_channel(&subchnl);	if (status < 0) {		DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));		return -EIO;	}	copy_to_user((void *) arg, &subchnl, sizeof subchnl);	return 0;}static int cdromread(unsigned long arg, int blocksize, int cmd){	int status;	struct cdrom_msf msf;	char buf[CD_FRAMESIZE_RAWER];	status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);	if (status)		return status;	copy_from_user(&msf, (void *) arg, sizeof msf);	bin2bcd(&msf);	msf.cdmsf_min1 = 0;	msf.cdmsf_sec1 = 0;	msf.cdmsf_frame1 = 1;	/* read only one frame */	status = exec_read_cmd(cmd, &msf);	DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));	if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))		return -EIO;	fetch_data(buf, blocksize);	copy_to_user((void *) arg, &buf, blocksize);	return 0;}static int cdromseek(unsigned long arg){	int status;	struct cdrom_msf msf;	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);	if (status)		return status;	copy_from_user(&msf, (void *) arg, sizeof msf);	bin2bcd(&msf);	status = exec_seek_cmd(COMSEEK, &msf);	DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));	if (status < 0)		return -EIO;	return 0;}#ifdef MULTISESSIONstatic int cdrommultisession(unsigned long arg){	int status;	struct cdrom_multisession ms;	status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);	if (status)		return status;	copy_from_user(&ms, (void*) arg, sizeof ms);	ms.addr.msf.minute = disk_info.last_session.minute;	ms.addr.msf.second = disk_info.last_session.second;	ms.addr.msf.frame = disk_info.last_session.frame;	if (ms.addr_format != CDROM_LBA	   && ms.addr_format != CDROM_MSF)		return -EINVAL;	if (ms.addr_format == CDROM_LBA)		msf2lba(&ms.addr);	ms.xa_flag = disk_info.xa;  	copy_to_user((void*) arg, &ms,		sizeof(struct cdrom_multisession));#if DEBUG_MULTIS 	if (ms.addr_format == CDROM_MSF)               	printk(KERN_DEBUG			"optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",			ms.xa_flag,			ms.addr.msf.minute,			ms.addr.msf.second,			ms.addr.msf.frame);	else		printk(KERN_DEBUG		    "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",			ms.xa_flag,			ms.addr.lba,			disk_info.last_session.minute,			disk_info.last_session.second,			disk_info.last_session.frame);#endif DEBUG_MULTIS	return 0;}#endif MULTISESSIONstatic int cdromreset(void){	if (state != S_IDLE) {		error = 1;		tries = 0;	}	toc_uptodate = 0;	disk_changed = 1;	opt_invalidate_buffers();	audio_status = CDROM_AUDIO_NO_STATUS;	if (!reset_drive())		return -EIO;	return 0;}/* VFS calls */static int opt_ioctl(struct inode *ip, struct file *fp,                     unsigned int cmd, unsigned long arg){	int status, err, retval = 0;	DEBUG((DEBUG_VFS, "starting opt_ioctl"));	if (!ip)		return -EINVAL;	if (cmd == CDROMRESET)		return cdromreset();	/* is do_optcd_request or another ioctl busy? */	if (state != S_IDLE || in_vfs)		return -EBUSY;	in_vfs = 1;	status = drive_status();	if (status < 0) {		DEBUG((DEBUG_VFS, "drive_status: %02x", -status));		in_vfs = 0;		return -EIO;	}	if (status & ST_DOOR_OPEN)		switch (cmd) {	/* Actions that can be taken with door open */		case CDROMCLOSETRAY:			/* We do this before trying to read the toc. */			err = exec_cmd(COMCLOSE);			if (err < 0) {				DEBUG((DEBUG_VFS,				       "exec_cmd COMCLOSE: %02x", -err));				in_vfs = 0;				return -EIO;			}			break;		default:	in_vfs = 0;				return -EBUSY;		}	err = update_toc();	if (err < 0) {		DEBUG((DEBUG_VFS, "update_toc: %02x", -err));		in_vfs = 0;		return -EIO;	}	DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));	switch (cmd) {	case CDROMPAUSE:	retval = cdrompause(); break;	case CDROMRESUME:	retval = cdromresume(); break;	case CDROMPLAYMSF:	retval = cdromplaymsf(arg); break;	case CDROMPLAYTRKIND:	retval = cdromplaytrkind(arg); break;	case CDROMREADTOCHDR:	retval = cdromreadtochdr(arg); break;	case CDROMREADTOCENTRY:	retval = cdromreadtocentry(arg); break;	case CDROMSTOP:		err = exec_cmd(COMSTOP);				if (err < 0) {					DEBUG((DEBUG_VFS,						"exec_cmd COMSTOP: %02x",						-err));					retval = -EIO;				} else					audio_status = CDROM_AUDIO_NO_STATUS;				break;	case CDROMSTART:	break;	/* This is a no-op */	case CDROMEJECT:	err = exec_cmd(COMUNLOCK);				if (err < 0) {					DEBUG((DEBUG_VFS,						"exec_cmd COMUNLOCK: %02x",						-err));					retval = -EIO;					break;				}				err = exec_cmd(COMOPEN);				if (err < 0) {					DEBUG((DEBUG_VFS,						"exec_cmd COMOPEN: %02x",						-err));					retval = -EIO;				}				break;	case CDROMVOLCTRL:	retval = cdromvolctrl(arg); break;	case CDROMSUBCHNL:	retval = cdromsubchnl(arg); break;	/* The drive detects the mode and automatically delivers the	   correct 2048 bytes, so we don't need these IOCTLs */	case CDROMREADMODE2:	retval = -EINVAL; break;	case CDROMREADMODE1:	retval = -EINVAL; break;	/* Drive doesn't support reading audio */	case CDROMREADAUDIO:	retval = -EINVAL; break;	case CDROMEJECT_SW:	auto_eject = (char) arg;				break;#ifdef MULTISESSION	case CDROMMULTISESSION:	retval = cdrommultisession(arg); break;#endif	case CDROM_GET_MCN:	retval = -EINVAL; break; /* not implemented */	case CDROMVOLREAD:	retval = -EINVAL; break; /* not implemented */	case CDROMREADRAW:			/* this drive delivers 2340 bytes in raw mode */			retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);			break;	case CDROMREADCOOKED:			retval = cdromread(arg, CD_FRAMESIZE, COMREAD);			break;	case CDROMREADALL:			retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);			break;	case CDROMSEEK:		retval = cdromseek(arg); break;	case CDROMPLAYBLK:	retval = -EINVAL; break; /* not implemented */	case CDROMCLOSETRAY:	break;	/* The action was taken earlier */	default:		retval = -EINVAL;	}	in_vfs = 0;	return retval;}static int open_count = 0;/* Open device special file; check that a disk is in. */static int opt_open(struct inode *ip, struct file *fp){	DEBUG((DEBUG_VFS, "starting opt_open"));	MOD_INC_USE_COUNT;	if (!open_count && state == S_IDLE) {		int status;		toc_uptodate = 0;		opt_invalidate_buffers();		status = exec_cmd(COMCLOSE);	/* close door */		if (status < 0) {			DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));		}		status = drive_status();		if (status < 0) {			DEBUG((DEBUG_VFS, "drive_status: %02x", -status));			goto err_out;		}		DEBUG((DEBUG_VFS, "status: %02x", status));		if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {			printk(KERN_INFO "optcd: no disk or door open\n");			goto err_out;		}		status = exec_cmd(COMLOCK);		/* Lock door */		if (status < 0) {			DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));		}		status = update_toc();	/* Read table of contents */		if (status < 0)	{			DEBUG((DEBUG_VFS, "update_toc: %02x", -status));	 		status = exec_cmd(COMUNLOCK);	/* Unlock door */			if (status < 0) {				DEBUG((DEBUG_VFS,				       "exec_cmd COMUNLOCK: %02x", -status));			}			goto err_out;		}		open_count++;	}	DEBUG((DEBUG_VFS, "exiting opt_open"));	return 0;err_out:    MOD_DEC_USE_COUNT;	return -EIO;}/* Release device special file; flush all blocks from the buffer cache */static int opt_release(struct inode *ip, struct file *fp){	int status;	DEBUG((DEBUG_VFS, "executing opt_release"));	DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",		ip, ip -> i_rdev, fp));	if (!--open_count) {		toc_uptodate = 0;		opt_invalidate_buffers();	 	status = exec_cmd(COMUNLOCK);	/* Unlock door */		if (status < 0) {			DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));		}		if (auto_eject) {			status = exec_cmd(COMOPEN);			DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));		}		del_timer(&delay_timer);		del_timer(&req_timer);	}	MOD_DEC_USE_COUNT;	return 0;}/* Check if disk has been changed */static int opt_media_change(kdev_t dev){	DEBUG((DEBUG_VFS, "executing opt_media_change"));	DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));	if (disk_changed) {		disk_changed = 0;		return 1;	}	return 0;}/* Driver initialisation *//* Returns 1 if a drive is detected with a version string   starting with "DOLPHIN". Otherwise 0. */static int __init version_ok(void){	char devname[100];	int count, i, ch, status;	status = exec_cmd(COMVERSION);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));		return 0;	}	if ((count = get_data(1)) < 0) {		DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));		return 0;	}	for (i = 0, ch = -1; count > 0; count--) {		if ((ch = get_data(1)) < 0) {			DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));			break;		}		if (i < 99)			devname[i++] = ch;	}	devname[i] = '\0';	if (ch < 0)		return 0;	printk(KERN_INFO "optcd: Device %s detected\n", devname);	return ((devname[0] == 'D')	     && (devname[1] == 'O')	     && (devname[2] == 'L')	     && (devname[3] == 'P')	     && (devname[4] == 'H')	     && (devname[5] == 'I')	     && (devname[6] == 'N'));}static struct block_device_operations opt_fops = {	open:			opt_open,	release:		opt_release,	ioctl:			opt_ioctl,	check_media_change:	opt_media_change,};#ifndef MODULE/* Get kernel parameter when used as a kernel driver */static int optcd_setup(char *str){	int ints[4];	(void)get_options(str, ARRAY_SIZE(ints), ints);		if (ints[0] > 0)		optcd_port = ints[1]; 	return 1;}__setup("optcd=", optcd_setup);#endif MODULE/* Test for presence of drive and initialize it. Called at boot time   or during module initialisation. */int __init optcd_init(void){	int status;	if (optcd_port <= 0) {		printk(KERN_INFO			"optcd: no Optics Storage CDROM Initialization\n");		return -EIO;	}	if (check_region(optcd_port, 4)) {		printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",			optcd_port);		return -EIO;	}	if (!reset_drive()) {		printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);		return -EIO;	}	if (!version_ok()) {		printk(KERN_ERR "optcd: unknown drive detected; aborting\n");		return -EIO;	}	status = exec_cmd(COMINITDOUBLE);	if (status < 0) {		printk(KERN_ERR "optcd: cannot init double speed mode\n");		DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));		return -EIO;	}	if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)	{		printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);		return -EIO;	}	devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,			S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);	hardsect_size[MAJOR_NR] = &hsecsize;	blksize_size[MAJOR_NR] = &blksize;	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);	read_ahead[MAJOR_NR] = 4;	request_region(optcd_port, 4, "optcd");	register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);	printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);	return 0;}void __exit optcd_exit(void){	devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,					   DEVFS_SPECIAL_BLK, 0));	if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {		printk(KERN_ERR "optcd: what's that: can't unregister\n");		return;	}	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));	release_region(optcd_port, 4);	printk(KERN_INFO "optcd: module released.\n");}#ifdef MODULEmodule_init(optcd_init);#endifmodule_exit(optcd_exit);

⌨️ 快捷键说明

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