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

📄 optcd.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	S_READ,		/* 2 */	S_DATA,		/* 3 */	S_STOP,		/* 4 */	S_STOPPING	/* 5 */};static volatile enum state_e state = S_IDLE;#if DEBUG_STATEstatic volatile enum state_e state_old = S_STOP;static volatile int flags_old = 0;static volatile long state_n = 0;#endif/* Used as mutex to keep do_optcd_request (and other processes calling   ioctl) out while some process is inside a VFS call.   Reverse is accomplished by checking if state = S_IDLE upon entry   of opt_ioctl and opt_media_change. */static int in_vfs = 0;static volatile int transfer_is_active = 0;static volatile int error = 0;	/* %% do something with this?? */static int tries;		/* ibid?? */static int timeout = 0;static void poll(unsigned long data);static struct timer_list req_timer = {function: poll};static void poll(unsigned long data){	static volatile int read_count = 1;	int flags;	int loop_again = 1;	int status = 0;	int skip = 0;	if (error) {		printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);		opt_invalidate_buffers();		if (!tries--) {			printk(KERN_ERR "optcd: read block %d failed;"				" Giving up\n", next_bn);			if (transfer_is_active)				loop_again = 0;			if (CURRENT_VALID)				end_request(0);			tries = 5;		}		error = 0;		state = S_STOP;	}	while (loop_again)	{		loop_again = 0; /* each case must flip this back to 1 if we want		                 to come back up here */#if DEBUG_STATE		if (state == state_old)			state_n++;		else {			state_old = state;			if (++state_n > 1)				printk(KERN_DEBUG "optcd: %ld times "					"in previous state\n", state_n);			printk(KERN_DEBUG "optcd: state %d\n", state);			state_n = 0;		}#endif		switch (state) {		case S_IDLE:			return;		case S_START:			if (in_vfs)				break;			if (send_cmd(COMDRVST)) {				state = S_IDLE;				while (CURRENT_VALID)					end_request(0);				return;			}			state = S_READ;			timeout = READ_TIMEOUT;			break;		case S_READ: {			struct cdrom_msf msf;			if (!skip) {				status = fetch_status();				if (status < 0)					break;				if (status & ST_DSK_CHG) {					toc_uptodate = 0;					opt_invalidate_buffers();				}			}			skip = 0;			if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {				toc_uptodate = 0;				opt_invalidate_buffers();				printk(KERN_WARNING "optcd: %s\n",					(status & ST_DOOR_OPEN)					? "door open"					: "disk removed");				state = S_IDLE;				while (CURRENT_VALID)					end_request(0);				return;			}			if (!CURRENT_VALID) {				state = S_STOP;				loop_again = 1;				break;			}			next_bn = CURRENT -> sector / 4;			lba2msf(next_bn, &msf);			read_count = N_BUFS;			msf.cdmsf_frame1 = read_count; /* Not BCD! */			DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",				msf.cdmsf_min0,				msf.cdmsf_sec0,				msf.cdmsf_frame0,				msf.cdmsf_min1,				msf.cdmsf_sec1,				msf.cdmsf_frame1));			DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"				" buf_out:%d buf_bn:%d",				next_bn,				buf_in,				buf_out,				buf_bn[buf_in]));			exec_read_cmd(COMREAD, &msf);			state = S_DATA;			timeout = READ_TIMEOUT;			break;		}		case S_DATA:			flags = stdt_flags() & (FL_STEN|FL_DTEN);#if DEBUG_STATE			if (flags != flags_old) {				flags_old = flags;				printk(KERN_DEBUG "optcd: flags:%x\n", flags);			}			if (flags == FL_STEN)				printk(KERN_DEBUG "timeout cnt: %d\n", timeout);#endif			switch (flags) {			case FL_DTEN:		/* only STEN low */				if (!tries--) {					printk(KERN_ERR						"optcd: read block %d failed; "						"Giving up\n", next_bn);					if (transfer_is_active) {						tries = 0;						break;					}					if (CURRENT_VALID)						end_request(0);					tries = 5;				}				state = S_START;				timeout = READ_TIMEOUT;				loop_again = 1;			case (FL_STEN|FL_DTEN):	 /* both high */				break;			default:	/* DTEN low */				tries = 5;				if (!CURRENT_VALID && buf_in == buf_out) {					state = S_STOP;					loop_again = 1;					break;				}				if (read_count<=0)					printk(KERN_WARNING						"optcd: warning - try to read"						" 0 frames\n");				while (read_count) {					buf_bn[buf_in] = NOBUF;					if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {					/* should be no waiting here!?? */						printk(KERN_ERR						   "read_count:%d "						   "CURRENT->nr_sectors:%ld "						   "buf_in:%d\n",							read_count,							CURRENT->nr_sectors,							buf_in);						printk(KERN_ERR							"transfer active: %x\n",							transfer_is_active);						read_count = 0;						state = S_STOP;						loop_again = 1;						end_request(0);						break;					}					fetch_data(buf+					    CD_FRAMESIZE*buf_in,					    CD_FRAMESIZE);					read_count--;					DEBUG((DEBUG_REQUEST,						"S_DATA; ---I've read data- "						"read_count: %d",						read_count));					DEBUG((DEBUG_REQUEST,						"next_bn:%d  buf_in:%d "						"buf_out:%d  buf_bn:%d",						next_bn,						buf_in,						buf_out,						buf_bn[buf_in]));					buf_bn[buf_in] = next_bn++;					if (buf_out == NOBUF)						buf_out = buf_in;					buf_in = buf_in + 1 ==						N_BUFS ? 0 : buf_in + 1;				}				if (!transfer_is_active) {					while (CURRENT_VALID) {						transfer();						if (CURRENT -> nr_sectors == 0)							end_request(1);						else							break;					}				}				if (CURRENT_VALID				    && (CURRENT -> sector / 4 < next_bn ||				    CURRENT -> sector / 4 >				     next_bn + N_BUFS)) {					state = S_STOP;					loop_again = 1;					break;				}				timeout = READ_TIMEOUT;				if (read_count == 0) {					state = S_STOP;					loop_again = 1;					break;				}			}			break;		case S_STOP:			if (read_count != 0)				printk(KERN_ERR					"optcd: discard data=%x frames\n",					read_count);			flush_data();			if (send_cmd(COMDRVST)) {				state = S_IDLE;				while (CURRENT_VALID)					end_request(0);				return;			}			state = S_STOPPING;			timeout = STOP_TIMEOUT;			break;		case S_STOPPING:			status = fetch_status();			if (status < 0 && timeout)					break;			if ((status >= 0) && (status & ST_DSK_CHG)) {				toc_uptodate = 0;				opt_invalidate_buffers();			}			if (CURRENT_VALID) {				if (status >= 0) {					state = S_READ;					loop_again = 1;					skip = 1;					break;				} else {					state = S_START;					timeout = 1;				}			} else {				state = S_IDLE;				return;			}			break;		default:			printk(KERN_ERR "optcd: invalid state %d\n", state);			return;		} /* case */	} /* while */	if (!timeout--) {		printk(KERN_ERR "optcd: timeout in state %d\n", state);		state = S_STOP;		if (exec_cmd(COMSTOP) < 0) {			state = S_IDLE;			while (CURRENT_VALID)				end_request(0);			return;		}	}	mod_timer(&req_timer, jiffies + HZ/100);}static void do_optcd_request(request_queue_t * q){	DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",	       CURRENT -> sector, CURRENT -> nr_sectors));	if (disk_info.audio) {		printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");		end_request(0);		return;	}	transfer_is_active = 1;	while (CURRENT_VALID) {		if (CURRENT->bh) {			if (!buffer_locked(CURRENT->bh))				panic(DEVICE_NAME ": block not locked");		}		transfer();	/* First try to transfer block from buffers */		if (CURRENT -> nr_sectors == 0) {			end_request(1);		} else {	/* Want to read a block not in buffer */			buf_out = NOBUF;			if (state == S_IDLE) {				/* %% Should this block the request queue?? */				if (update_toc() < 0) {					while (CURRENT_VALID)						end_request(0);					break;				}				/* Start state machine */				state = S_START;				timeout = READ_TIMEOUT;				tries = 5;				/* %% why not start right away?? */				mod_timer(&req_timer, jiffies + HZ/100);			}			break;		}	}	transfer_is_active = 0;	DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",	       next_bn, buf_in, buf_out, buf_bn[buf_in]));	DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));}/* IOCTLs */static char auto_eject = 0;static int cdrompause(void){	int status;	if (audio_status != CDROM_AUDIO_PLAY)		return -EINVAL;	status = exec_cmd(COMPAUSEON);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));		return -EIO;	}	audio_status = CDROM_AUDIO_PAUSED;	return 0;}static int cdromresume(void){	int status;	if (audio_status != CDROM_AUDIO_PAUSED)		return -EINVAL;	status = exec_cmd(COMPAUSEOFF);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));		audio_status = CDROM_AUDIO_ERROR;		return -EIO;	}	audio_status = CDROM_AUDIO_PLAY;	return 0;}static int cdromplaymsf(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_long_cmd(COMPLAY, &msf);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));		audio_status = CDROM_AUDIO_ERROR;		return -EIO;	}	audio_status = CDROM_AUDIO_PLAY;	return 0;}static int cdromplaytrkind(unsigned long arg){	int status;	struct cdrom_ti ti;	struct cdrom_msf msf;	status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);	if (status)		return status;	copy_from_user(&ti, (void *) arg, sizeof ti);	if (ti.cdti_trk0 < disk_info.first	    || ti.cdti_trk0 > disk_info.last	    || ti.cdti_trk1 < ti.cdti_trk0)		return -EINVAL;	if (ti.cdti_trk1 > disk_info.last)		ti.cdti_trk1 = disk_info.last;	msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;	msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;	msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;	msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;	msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;	msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;	DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",		msf.cdmsf_min0,		msf.cdmsf_sec0,		msf.cdmsf_frame0,		msf.cdmsf_min1,		msf.cdmsf_sec1,		msf.cdmsf_frame1));	bin2bcd(&msf);	status = exec_long_cmd(COMPLAY, &msf);	if (status < 0) {		DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));		audio_status = CDROM_AUDIO_ERROR;		return -EIO;	}	audio_status = CDROM_AUDIO_PLAY;	return 0;}static int cdromreadtochdr(unsigned long arg){	int status;	struct cdrom_tochdr tochdr;	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);	if (status)		return status;	tochdr.cdth_trk0 = disk_info.first;	tochdr.cdth_trk1 = disk_info.last;	copy_to_user((void *) arg, &tochdr, sizeof tochdr);	return 0;}static int cdromreadtocentry(unsigned long arg){	int status;	struct cdrom_tocentry entry;	struct cdrom_subchnl *tocptr;	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);	if (status)		return status;	copy_from_user(&entry, (void *) arg, sizeof entry);	if (entry.cdte_track == CDROM_LEADOUT)		tocptr = &toc[disk_info.last + 1];	else if (entry.cdte_track > disk_info.last		|| entry.cdte_track < disk_info.first)		return -EINVAL;	else		tocptr = &toc[entry.cdte_track];	entry.cdte_adr = tocptr->cdsc_adr;	entry.cdte_ctrl = tocptr->cdsc_ctrl;	entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;	entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;	entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;	/* %% What should go into entry.cdte_datamode? */	if (entry.cdte_format == CDROM_LBA)		msf2lba(&entry.cdte_addr);	else if (entry.cdte_format != CDROM_MSF)		return -EINVAL;	copy_to_user((void *) arg, &entry, sizeof entry);	return 0;}static int cdromvolctrl(unsigned long arg){	int status;	struct cdrom_volctrl volctrl;	struct cdrom_msf msf;	status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);

⌨️ 快捷键说明

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