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

📄 mcd.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 3 页
字号:
/* This routine gets called during initialization if things go wrong, * and is used in mcd_exit as well. */static void cleanup(int level){	switch (level) {	case 3:		if (unregister_cdrom(&mcd_info)) {			printk(KERN_WARNING "Can't unregister cdrom mcd\n");			return;		}		free_irq(mcd_irq, NULL);	case 2:		release_region(mcd_port, 4);	case 1:		if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {			printk(KERN_WARNING "Can't unregister major mcd\n");			return;		}		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));	default:;	}}/* * Test for presence of drive and initialize it.  Called at boot time. */int __init mcd_init(void){	int count;	unsigned char result[3];	char msg[80];	if (mcd_port <= 0 || mcd_irq <= 0) {		printk(KERN_INFO "mcd: not probing.\n");		return -EIO;	}	if (devfs_register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) {		printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);		return -EIO;	}	if (check_region(mcd_port, 4)) {		cleanup(1);		printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);		return -EIO;	}	blksize_size[MAJOR_NR] = mcd_blocksizes;	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);	read_ahead[MAJOR_NR] = 4;	/* check for card */	outb(0, MCDPORT(1));	/* send reset */	for (count = 0; count < 2000000; count++)		(void) inb(MCDPORT(1));	/* delay a bit */	outb(0x40, MCDPORT(0));	/* send get-stat cmd */	for (count = 0; count < 2000000; count++)		if (!(inb(MCDPORT(1)) & MFL_STATUS))			break;	if (count >= 2000000) {		printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",		       mcd_port, mcd_irq);		cleanup(1);		return -EIO;	}	count = inb(MCDPORT(0));	/* pick up the status */	outb(MCMD_GET_VERSION, MCDPORT(0));	for (count = 0; count < 3; count++)		if (getValue(result + count)) {			printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",			       mcd_port);			cleanup(1);			return -EIO;		}	if (result[0] == result[1] && result[1] == result[2]) {		cleanup(1);		return -EIO;	}	mcdVersion = result[2];	if (mcdVersion >= 4)		outb(4, MCDPORT(2));	/* magic happens */	/* don't get the IRQ until we know for sure the drive is there */	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {		printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);		cleanup(1);		return -EIO;	}	if (result[1] == 'D') {		MCMD_DATA_READ = MCMD_2X_READ;		/* Added flag to drop to 1x speed if too many errors */		mcdDouble = 1;	} else		mcd_info.speed = 1;	sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"		" irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",		mcd_port, mcd_irq);	request_region(mcd_port, 4, "mcd");	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));	outb(0x02, MCDPORT(0));	outb(0x00, MCDPORT(0));	getValue(result);	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));	outb(0x10, MCDPORT(0));	outb(0x04, MCDPORT(0));	getValue(result);	mcd_invalidate_buffers();	mcdPresent = 1;	mcd_info.dev = MKDEV(MAJOR_NR, 0);	if (register_cdrom(&mcd_info) != 0) {		printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");		cleanup(3);		return -EIO;	}	devfs_plain_cdrom(&mcd_info, &mcd_bdops);	printk(msg);	return 0;}static void hsg2msf(long hsg, struct msf *msf){	hsg += 150;	msf->min = hsg / 4500;	hsg %= 4500;	msf->sec = hsg / 75;	msf->frame = hsg % 75;	bin2bcd(&msf->min);	/* convert to BCD */	bin2bcd(&msf->sec);	bin2bcd(&msf->frame);}static void bin2bcd(unsigned char *p){	int u, t;	u = *p % 10;	t = *p / 10;	*p = u | (t << 4);}static int bcd2bin(unsigned char bcd){	return (bcd >> 4) * 10 + (bcd & 0xF);}/* * See if a status is ready from the drive and return it * if it is ready. */static int mcdStatus(void){	int i;	int st;	st = inb(MCDPORT(1)) & MFL_STATUS;	if (!st) {		i = inb(MCDPORT(0)) & 0xFF;		return i;	} else		return -1;}/* * Send a play or read command to the drive */static void sendMcdCmd(int cmd, struct mcd_Play_msf *params){	outb(cmd, MCDPORT(0));	outb(params->start.min, MCDPORT(0));	outb(params->start.sec, MCDPORT(0));	outb(params->start.frame, MCDPORT(0));	outb(params->end.min, MCDPORT(0));	outb(params->end.sec, MCDPORT(0));	outb(params->end.frame, MCDPORT(0));}/* * Timer interrupt routine to test for status ready from the drive. * (see the next routine) */static void mcdStatTimer(unsigned long dummy){	if (!(inb(MCDPORT(1)) & MFL_STATUS)) {		wake_up(&mcd_waitq);		return;	}	McdTimeout--;	if (McdTimeout <= 0) {		wake_up(&mcd_waitq);		return;	}	mcd_timer.function = mcdStatTimer;	mod_timer(&mcd_timer, jiffies + 1);}/* * Wait for a status to be returned from the drive.  The actual test * (see routine above) is done by the timer interrupt to avoid * excessive rescheduling. */static int getMcdStatus(int timeout){	int st;	McdTimeout = timeout;	mcd_timer.function = mcdStatTimer;	mod_timer(&mcd_timer, jiffies + 1);	sleep_on(&mcd_waitq);	if (McdTimeout <= 0)		return -1;	st = inb(MCDPORT(0)) & 0xFF;	if (st == 0xFF)		return -1;	if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)		/* XXX might be an error? look at q-channel? */		audioStatus = CDROM_AUDIO_COMPLETED;	if (st & MST_DSK_CHG) {		mcdDiskChanged = 1;		tocUpToDate = 0;		audioStatus = CDROM_AUDIO_NO_STATUS;	}	return st;}/* gives current state of the drive This function is quite unreliable,    and should probably be rewritten by someone, eventually... */int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr){	int st;	st = statusCmd();	/* check drive status */	if (st == -1)		return -EIO;	/* drive doesn't respond */	if ((st & MST_READY))		return CDS_DISC_OK;	if ((st & MST_DOOR_OPEN))		return CDS_TRAY_OPEN;	if ((st & MST_DSK_CHG))		return CDS_NO_DISC;	if ((st & MST_BUSY))		return CDS_DRIVE_NOT_READY;	return -EIO;}/* * Read a value from the drive. */static int getValue(unsigned char *result){	int count;	int s;	for (count = 0; count < 2000; count++)		if (!(inb(MCDPORT(1)) & MFL_STATUS))			break;	if (count >= 2000) {		printk("mcd: getValue timeout\n");		return -1;	}	s = inb(MCDPORT(0)) & 0xFF;	*result = (unsigned char) s;	return 0;}/* * Read the current Q-channel info.  Also used for reading the * table of contents. */int GetQChannelInfo(struct mcd_Toc *qp){	unsigned char notUsed;	int retry;	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {		outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));		if (getMcdStatus(MCD_STATUS_DELAY) != -1)			break;	}	if (retry >= MCD_RETRY_ATTEMPTS)		return -1;	if (getValue(&qp->ctrl_addr) < 0)		return -1;	if (getValue(&qp->track) < 0)		return -1;	if (getValue(&qp->pointIndex) < 0)		return -1;	if (getValue(&qp->trackTime.min) < 0)		return -1;	if (getValue(&qp->trackTime.sec) < 0)		return -1;	if (getValue(&qp->trackTime.frame) < 0)		return -1;	if (getValue(&notUsed) < 0)		return -1;	if (getValue(&qp->diskTime.min) < 0)		return -1;	if (getValue(&qp->diskTime.sec) < 0)		return -1;	if (getValue(&qp->diskTime.frame) < 0)		return -1;	return 0;}/* * Read the table of contents (TOC) and TOC header if necessary */static int updateToc(void){	if (tocUpToDate)		return 0;	if (GetDiskInfo() < 0)		return -EIO;	if (GetToc() < 0)		return -EIO;	tocUpToDate = 1;	return 0;}/* * Read the table of contents header */static int GetDiskInfo(void){	int retry;	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {		outb(MCMD_GET_DISK_INFO, MCDPORT(0));		if (getMcdStatus(MCD_STATUS_DELAY) != -1)			break;	}	if (retry >= MCD_RETRY_ATTEMPTS)		return -1;	if (getValue(&DiskInfo.first) < 0)		return -1;	if (getValue(&DiskInfo.last) < 0)		return -1;	DiskInfo.first = bcd2bin(DiskInfo.first);	DiskInfo.last = bcd2bin(DiskInfo.last);#ifdef MCD_DEBUG	printk	    ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",	     DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,	     DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,	     DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,	     DiskInfo.firstTrack.frame);#endif	if (getValue(&DiskInfo.diskLength.min) < 0)		return -1;	if (getValue(&DiskInfo.diskLength.sec) < 0)		return -1;	if (getValue(&DiskInfo.diskLength.frame) < 0)		return -1;	if (getValue(&DiskInfo.firstTrack.min) < 0)		return -1;	if (getValue(&DiskInfo.firstTrack.sec) < 0)		return -1;	if (getValue(&DiskInfo.firstTrack.frame) < 0)		return -1;	return 0;}/* * Read the table of contents (TOC) */static int GetToc(void){	int i, px;	int limit;	int retry;	struct mcd_Toc qInfo;	for (i = 0; i < MAX_TRACKS; i++)		Toc[i].pointIndex = 0;	i = DiskInfo.last + 3;	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {		outb(MCMD_STOP, MCDPORT(0));		if (getMcdStatus(MCD_STATUS_DELAY) != -1)			break;	}	if (retry >= MCD_RETRY_ATTEMPTS)		return -1;	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {		outb(MCMD_SET_MODE, MCDPORT(0));		outb(0x05, MCDPORT(0));	/* mode: toc */		mcd_mode = 0x05;		if (getMcdStatus(MCD_STATUS_DELAY) != -1)			break;	}	if (retry >= MCD_RETRY_ATTEMPTS)		return -1;	for (limit = 300; limit > 0; limit--) {		if (GetQChannelInfo(&qInfo) < 0)			break;		px = bcd2bin(qInfo.pointIndex);		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)			if (Toc[px].pointIndex == 0) {				Toc[px] = qInfo;				i--;			}		if (i <= 0)			break;	}	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;	for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {		outb(MCMD_SET_MODE, MCDPORT(0));		outb(0x01, MCDPORT(0));		mcd_mode = 1;		if (getMcdStatus(MCD_STATUS_DELAY) != -1)			break;	}#ifdef MCD_DEBUG	for (i = 1; i <= DiskInfo.last; i++)		printk		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,		     Toc[i].trackTime.min, Toc[i].trackTime.sec,		     Toc[i].trackTime.frame, Toc[i].diskTime.min,		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);	for (i = 100; i < 103; i++)		printk		    ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",		     i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,		     Toc[i].trackTime.min, Toc[i].trackTime.sec,		     Toc[i].trackTime.frame, Toc[i].diskTime.min,		     Toc[i].diskTime.sec, Toc[i].diskTime.frame);#endif	return limit > 0 ? 0 : -1;}void __exit mcd_exit(void){	cleanup(3);	del_timer_sync(&mcd_timer);}#ifdef MODULEmodule_init(mcd_init);#endifmodule_exit(mcd_exit);MODULE_AUTHOR("Martin Harriss");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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