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

📄 cm206.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 3 页
字号:
	cd->dsb = wait_dsb();}int get_current_q(struct cdrom_subchnl *qp){	int i;	uch *q = cd->q;	if (type_1_command(c_read_current_q, 10, q))		return 0;/*  q[0] = bcdbin(q[0]); Don't think so! */	for (i = 2; i < 6; i++)		q[i] = bcdbin(q[i]);	qp->cdsc_adr = q[0] & 0xf;	qp->cdsc_ctrl = q[0] >> 4;	/* from mcd.c */	qp->cdsc_trk = q[1];	qp->cdsc_ind = q[2];	if (qp->cdsc_format == CDROM_MSF) {		qp->cdsc_reladdr.msf.minute = q[3];		qp->cdsc_reladdr.msf.second = q[4];		qp->cdsc_reladdr.msf.frame = q[5];		qp->cdsc_absaddr.msf.minute = q[7];		qp->cdsc_absaddr.msf.second = q[8];		qp->cdsc_absaddr.msf.frame = q[9];	} else {		qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]);		qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]);	}	get_drive_status();	if (cd->dsb & dsb_play_in_progress)		qp->cdsc_audiostatus = CDROM_AUDIO_PLAY;	else if (PAUSED)		qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED;	else		qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS;	return 0;}void invalidate_toc(void){	memset(cd->toc, 0, sizeof(cd->toc));	memset(cd->disc_status, 0, sizeof(cd->disc_status));}/* cdrom.c guarantees that cdte_format == CDROM_MSF */void get_toc_entry(struct cdrom_tocentry *ep){	uch track = normalize_track(ep->cdte_track);	update_toc_entry(track);	ep->cdte_addr.msf.frame = cd->toc[track].fsm[0];	ep->cdte_addr.msf.second = cd->toc[track].fsm[1];	ep->cdte_addr.msf.minute = cd->toc[track].fsm[2];	ep->cdte_adr = cd->toc[track].q0 & 0xf;	ep->cdte_ctrl = cd->toc[track].q0 >> 4;	ep->cdte_datamode = 0;}/* Audio ioctl.  Ioctl commands connected to audio are in such an * idiosyncratic i/o format, that we leave these untouched. Return 0 * upon success. Memory checking has been done by cdrom_ioctl(), the * calling function, as well as LBA/MSF sanitization.*/int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,		      void *arg){	switch (cmd) {	case CDROMREADTOCHDR:		return read_toc_header((struct cdrom_tochdr *) arg);	case CDROMREADTOCENTRY:		get_toc_entry((struct cdrom_tocentry *) arg);		return 0;	case CDROMPLAYMSF:		play_from_to_msf((struct cdrom_msf *) arg);		return 0;	case CDROMPLAYTRKIND:	/* admittedly, not particularly beautiful */		play_from_to_track(((struct cdrom_ti *) arg)->cdti_trk0,				   ((struct cdrom_ti *) arg)->cdti_trk1);		return 0;	case CDROMSTOP:		PAUSED = 0;		if (cd->dsb & dsb_play_in_progress)			return type_0_command(c_stop, 1);		else			return 0;	case CDROMPAUSE:		get_drive_status();		if (cd->dsb & dsb_play_in_progress) {			type_0_command(c_stop, 1);			type_1_command(c_audio_status, 5,				       cd->audio_status);			PAUSED = 1;	/* say we're paused */		}		return 0;	case CDROMRESUME:		if (PAUSED)			play_from_to_track(0, 0);		PAUSED = 0;		return 0;	case CDROMSTART:	case CDROMVOLCTRL:		return 0;	case CDROMSUBCHNL:		return get_current_q((struct cdrom_subchnl *) arg);	default:		return -EINVAL;	}}/* Ioctl. These ioctls are specific to the cm206 driver. I have made   some driver statistics accessible through ioctl calls. */static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,		       unsigned long arg){	switch (cmd) {#ifdef STATISTICS	case CM206CTL_GET_STAT:		if (arg >= NR_STATS)			return -EINVAL;		else			return cd->stats[arg];	case CM206CTL_GET_LAST_STAT:		if (arg >= NR_STATS)			return -EINVAL;		else			return cd->last_stat[arg];#endif	default:		debug(("Unknown ioctl call 0x%x\n", cmd));		return -EINVAL;	}}int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr){	if (cd != NULL) {		int r;		get_drive_status();	/* ensure cd->media_changed OK */		r = cd->media_changed;		cd->media_changed = 0;	/* clear bit */		return r;	} else		return -EIO;}/* The new generic cdrom support. Routines should be concise, most of   the logic should be in cdrom.c *//* returns number of times device is in use */int cm206_open_files(struct cdrom_device_info *cdi){	if (cd)		return cd->openfiles;	return -1;}/* controls tray movement */int cm206_tray_move(struct cdrom_device_info *cdi, int position){	if (position) {		/* 1: eject */		type_0_command(c_open_tray, 1);		invalidate_toc();	} else		type_0_command(c_close_tray, 1);	/* 0: close */	return 0;}/* gives current state of the drive */int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr){	get_drive_status();	if (cd->dsb & dsb_tray_not_closed)		return CDS_TRAY_OPEN;	if (!(cd->dsb & dsb_disc_present))		return CDS_NO_DISC;	if (cd->dsb & dsb_drive_not_ready)		return CDS_DRIVE_NOT_READY;	return CDS_DISC_OK;}/* locks or unlocks door lock==1: lock; return 0 upon success */int cm206_lock_door(struct cdrom_device_info *cdi, int lock){	uch command = (lock) ? c_lock_tray : c_unlock_tray;	type_0_command(command, 1);	/* wait and get dsb */	/* the logic calculates the success, 0 means successful */	return lock ^ ((cd->dsb & dsb_tray_locked) != 0);}/* Although a session start should be in LBA format, we return it in    MSF format because it is slightly easier, and the new generic ioctl   will take care of the necessary conversion. */int cm206_get_last_session(struct cdrom_device_info *cdi,			   struct cdrom_multisession *mssp){	if (!FIRST_TRACK)		get_disc_status();	if (mssp != NULL) {		if (DISC_STATUS & cds_multi_session) {	/* multi-session */			mssp->addr.msf.frame = cd->disc_status[3];			mssp->addr.msf.second = cd->disc_status[4];			mssp->addr.msf.minute = cd->disc_status[5];			mssp->addr_format = CDROM_MSF;			mssp->xa_flag = 1;		} else {			mssp->xa_flag = 0;		}		return 1;	}	return 0;}int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn){	uch upc[10];	char *ret = mcn->medium_catalog_number;	int i;	if (type_1_command(c_read_upc, 10, upc))		return -EIO;	for (i = 0; i < 13; i++) {		int w = i / 2 + 1, r = i % 2;		if (r)			ret[i] = 0x30 | (upc[w] & 0x0f);		else			ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f);	}	ret[13] = '\0';	return 0;}int cm206_reset(struct cdrom_device_info *cdi){	stop_read();	reset_cm260();	outw(dc_normal | dc_break | READ_AHEAD, r_data_control);	mdelay(1);		/* 750 musec minimum */	outw(dc_normal | READ_AHEAD, r_data_control);	cd->sector_last = -1;	/* flag no data buffered */	cd->adapter_last = -1;	invalidate_toc();	return 0;}int cm206_select_speed(struct cdrom_device_info *cdi, int speed){	int r;	switch (speed) {	case 0:		r = type_0_command(c_auto_mode, 1);		break;	case 1:		r = type_0_command(c_force_1x, 1);		break;	case 2:		r = type_0_command(c_force_2x, 1);		break;	default:		return -1;	}	if (r < 0)		return r;	else		return 1;}static struct cdrom_device_ops cm206_dops = {	open:cm206_open,	release:cm206_release,	drive_status:cm206_drive_status,	media_changed:cm206_media_changed,	tray_move:cm206_tray_move,	lock_door:cm206_lock_door,	select_speed:cm206_select_speed,	get_last_session:cm206_get_last_session,	get_mcn:cm206_get_upc,	reset:cm206_reset,	audio_ioctl:cm206_audio_ioctl,	dev_ioctl:cm206_ioctl,	capability:CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |	    CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |	    CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED |	    CDC_IOCTLS | CDC_DRIVE_STATUS,	n_minors:1,};static struct cdrom_device_info cm206_info = {	ops:&cm206_dops,	speed:2,	capacity:1,	name:"cm206",};/* This routine gets called during initialization if things go wrong, * can be used in cleanup_module as well. */static void cleanup(int level){	switch (level) {	case 4:		if (unregister_cdrom(&cm206_info)) {			printk("Can't unregister cdrom cm206\n");			return;		}		if (devfs_unregister_blkdev(MAJOR_NR, "cm206")) {			printk("Can't unregister major cm206\n");			return;		}		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));	case 3:		free_irq(cm206_irq, NULL);	case 2:	case 1:		kfree(cd);		release_region(cm206_base, 16);	default:;	}}/* This function probes for the adapter card. It returns the base   address if it has found the adapter card. One can specify a base    port to probe specifically, or 0 which means span all possible   bases.    Linus says it is too dangerous to use writes for probing, so we   stick with pure reads for a while. Hope that 8 possible ranges,   check_region, 15 bits of one port and 6 of another make things   likely enough to accept the region on the first hit... */int __init probe_base_port(int base){	int b = 0x300, e = 0x370;	/* this is the range of start addresses */	volatile int fool, i;	if (base)		b = e = base;	for (base = b; base <= e; base += 0x10) {		if (check_region(base, 0x10))			continue;		for (i = 0; i < 3; i++)			fool = inw(base + 2);	/* empty possibly uart_receive_buffer */		if ((inw(base + 6) & 0xffef) != 0x0001 ||	/* line_status */		    (inw(base) & 0xad00) != 0)	/* data status */			continue;		return (base);	}	return 0;}#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)/* Probe for irq# nr. If nr==0, probe for all possible irq's. */int __init probe_irq(int nr){	int irqs, irq;	outw(dc_normal | READ_AHEAD, r_data_control);	/* disable irq-generation */	sti();	irqs = probe_irq_on();	reset_cm260();		/* causes interrupt */	udelay(100);		/* wait for it */	irq = probe_irq_off(irqs);	outw(dc_normal | READ_AHEAD, r_data_control);	/* services interrupt */	if (nr && irq != nr && irq > 0)		return 0;	/* wrong interrupt happened */	else		return irq;}#endifint __init cm206_init(void){	uch e = 0;	long int size = sizeof(struct cm206_struct);	printk(KERN_INFO "cm206 cdrom driver " REVISION);	cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);	if (!cm206_base) {		printk(" can't find adapter!\n");		return -EIO;	}	printk(" adapter at 0x%x", cm206_base);	request_region(cm206_base, 16, "cm206");	cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL);	if (!cd)		return -EIO;	/* Now we have found the adaptor card, try to reset it. As we have	 * found out earlier, this process generates an interrupt as well,	 * so we might just exploit that fact for irq probing! */#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)	cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq);	if (cm206_irq <= 0) {		printk("can't find IRQ!\n");		cleanup(1);		return -EIO;	} else		printk(" IRQ %d found\n", cm206_irq);#else	cli();	reset_cm260();	/* Now, the problem here is that reset_cm260 can generate an	   interrupt. It seems that this can cause a kernel oops some time	   later. So we wait a while and `service' this interrupt. */	mdelay(1);	outw(dc_normal | READ_AHEAD, r_data_control);	sti();	printk(" using IRQ %d\n", cm206_irq);#endif	if (send_receive_polled(c_drive_configuration) !=	    c_drive_configuration) {		printk(KERN_INFO " drive not there\n");		cleanup(1);		return -EIO;	}	e = send_receive_polled(c_gimme);	printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code);	if (e & dcf_transfer_rate)		printk(" double");	else		printk(" single");	printk(" speed drive");	if (e & dcf_motorized_tray)		printk(", motorized tray");	if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) {		printk("\nUnable to reserve IRQ---aborted\n");		cleanup(2);		return -EIO;	}	printk(".\n");	if (devfs_register_blkdev(MAJOR_NR, "cm206", &cm206_bdops) != 0) {		printk(KERN_INFO "Cannot register for major %d!\n",		       MAJOR_NR);		cleanup(3);		return -EIO;	}	cm206_info.dev = MKDEV(MAJOR_NR, 0);	if (register_cdrom(&cm206_info) != 0) {		printk(KERN_INFO "Cannot register for cdrom %d!\n",		       MAJOR_NR);		cleanup(3);		return -EIO;	}	devfs_plain_cdrom(&cm206_info, &cm206_bdops);	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);	blksize_size[MAJOR_NR] = cm206_blocksizes;	read_ahead[MAJOR_NR] = 16;	/* reads ahead what? */	init_bh(CM206_BH, cm206_bh);	memset(cd, 0, sizeof(*cd));	/* give'm some reasonable value */	cd->sector_last = -1;	/* flag no data buffered */	cd->adapter_last = -1;	cd->timer.function = cm206_timeout;	cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97;	printk(KERN_INFO "%d kB adapter memory available, "	       " %ld bytes kernel memory used.\n", cd->max_sectors * 2,	       size);	return 0;}#ifdef MODULEstatic void __init parse_options(void){	int i;	for (i = 0; i < 2; i++) {		if (0x300 <= cm206[i] && i <= 0x370		    && cm206[i] % 0x10 == 0) {			cm206_base = cm206[i];			auto_probe = 0;		} else if (3 <= cm206[i] && cm206[i] <= 15) {			cm206_irq = cm206[i];			auto_probe = 0;		}	}}int __cm206_init(void){	parse_options();#if !defined(AUTO_PROBE_MODULE)	auto_probe = 0;#endif	return cm206_init();}void __exit cm206_exit(void){	cleanup(4);	printk(KERN_INFO "cm206 removed\n");}module_init(__cm206_init);module_exit(cm206_exit);#else				/* !MODULE *//* This setup function accepts either `auto' or numbers in the range * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */static int __init cm206_setup(char *s){	int i, p[4];	(void) get_options(s, ARRAY_SIZE(p), p);	if (!strcmp(s, "auto"))		auto_probe = 1;	for (i = 1; i <= p[0]; i++) {		if (0x300 <= p[i] && i <= 0x370 && p[i] % 0x10 == 0) {			cm206_base = p[i];			auto_probe = 0;		} else if (3 <= p[i] && p[i] <= 15) {			cm206_irq = p[i];			auto_probe = 0;		}	}	return 1;}__setup("cm206=", cm206_setup);#endif				/* !MODULE *//* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cm206.o cm206.c" * End: */

⌨️ 快捷键说明

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