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

📄 mcdx.c

📁 powerpc内核 mpc8241芯片 linux系统下cdrom驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
        sz--;        if (!discard) bp++;        xtrace(TALK, "talk() got status 0x%02x\n", st);        /* command error? */        if (e_cmderr(st)) {            xwarn("command error cmd = %02x %s \n",                    cmd[0], cmdlen > 1 ? "..." : "");            st = -1;            continue;		}        /* audio status? */        if (stuffp->audiostatus == CDROM_AUDIO_INVALID)            stuffp->audiostatus =                    e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;        else if (stuffp->audiostatus == CDROM_AUDIO_PLAY                && e_audiobusy(st) == 0)            stuffp->audiostatus = CDROM_AUDIO_COMPLETED;        /* media change? */        if (e_changed(st)) {            xinfo("talk() media changed\n");            stuffp->xxx = stuffp->yyy = 1;        }        /* now actually get the data */        while (sz--) {            if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {                xinfo("talk() %02x timed out (data), %d tr%s left\n",                        cmd[0], tries - 1, tries == 2 ? "y" : "ies");                st = -1; break;            }            if (!discard) bp++;            xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));        }    }#if !MCDX_QUIET    if (!tries && st == -1) xinfo("talk() giving up\n");#endif    stuffp->lock = 0;    wake_up_interruptible(&stuffp->lockq);	xtrace(TALK, "talk() done with 0x%02x\n", st);    return st;}/* MODULE STUFF ***********************************************************/#ifdef MODULEEXPORT_NO_SYMBOLS;int init_module(void){	int i;	int drives = 0;	mcdx_init();	for (i = 0; i < MCDX_NDRIVES; i++)  {		if (mcdx_stuffp[i]) {		xtrace(INIT, "init_module() drive %d stuff @ %p\n",				i, mcdx_stuffp[i]);			drives++;		}	}    if (!drives)		return -EIO;    return 0;}void cleanup_module(void){    int i;	xinfo("cleanup_module called\n");    for (i = 0; i < MCDX_NDRIVES; i++) {		struct s_drive_stuff *stuffp;        if (unregister_cdrom(&mcdx_info)) {			printk(KERN_WARNING "Can't unregister cdrom mcdx\n");			return;		}		stuffp = mcdx_stuffp[i];		if (!stuffp) continue;		release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);		free_irq(stuffp->irq, NULL);		if (stuffp->toc) {			xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc);			kfree(stuffp->toc);		}		xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp);		mcdx_stuffp[i] = NULL;		kfree(stuffp);    }    if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {        xwarn("cleanup() unregister_blkdev() failed\n");    }#if !MCDX_QUIET	else xinfo("cleanup() succeeded\n");#endif}#endif MODULE/* Support functions ************************************************/__initfunc(int mcdx_init_drive(int drive)){	struct s_version version;	struct s_drive_stuff* stuffp;	int size = sizeof(*stuffp);	char msg[80];	mcdx_blocksizes[drive] = 0;	xtrace(INIT, "init() try drive %d\n", drive);	xtrace(INIT, "kmalloc space for stuffpt's\n");	xtrace(MALLOC, "init() malloc %d bytes\n", size);	if (!(stuffp = kmalloc(size, GFP_KERNEL))) {		xwarn("init() malloc failed\n");		return 1;	}	xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",	       sizeof(*stuffp), stuffp);	/* set default values */	memset(stuffp, 0, sizeof(*stuffp));	stuffp->present = 0;	/* this should be 0 already */	stuffp->toc = NULL;	/* this should be NULL already */	/* setup our irq and i/o addresses */	stuffp->irq = irq(mcdx_drive_map[drive]);	stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);	stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;	stuffp->wreg_hcon = stuffp->wreg_reset + 1;	stuffp->wreg_chn = stuffp->wreg_hcon + 1;	/* check if i/o addresses are available */	if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {		xwarn("0x%3p,%d: Init failed. "		      "I/O ports (0x%3p..0x%3p) already in use.\n",		      stuffp->wreg_data, stuffp->irq,		      stuffp->wreg_data,		      stuffp->wreg_data + MCDX_IO_SIZE - 1);		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);		kfree(stuffp);		xtrace(INIT, "init() continue at next drive\n");		return 0; /* next drive */	}	xtrace(INIT, "init() i/o port is available at 0x%3p\n",	       stuffp->wreg_data);	xtrace(INIT, "init() hardware reset\n");	mcdx_reset(stuffp, HARD, 1);	xtrace(INIT, "init() get version\n");	if (-1 == mcdx_requestversion(stuffp, &version, 4)) {		/* failed, next drive */		xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",		      MCDX,		      stuffp->wreg_data, stuffp->irq);		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);		kfree(stuffp);		xtrace(INIT, "init() continue at next drive\n");		return 0;	}	switch (version.code) {	case 'D':                stuffp->readcmd = READ2X;                stuffp->present = DOUBLE | DOOR | MULTI;                break;	case 'F':                stuffp->readcmd = READ1X;                stuffp->present = SINGLE | DOOR | MULTI;                break;	case 'M':                stuffp->readcmd = READ1X;                stuffp->present = SINGLE;                break;	default:                stuffp->present = 0; break;	}        stuffp->playcmd = READ1X;	if (!stuffp->present) {		xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",		      MCDX, stuffp->wreg_data, stuffp->irq);		kfree(stuffp);		return 0; /* next drive */	}	xtrace(INIT, "init() register blkdev\n");	if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) {		xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",		      MCDX,		      stuffp->wreg_data, stuffp->irq, MAJOR_NR);		kfree(stuffp);		return 1;	}	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;	read_ahead[MAJOR_NR] = READ_AHEAD;	blksize_size[MAJOR_NR] = mcdx_blocksizes;	xtrace(INIT, "init() subscribe irq and i/o\n");	mcdx_irq_map[stuffp->irq] = stuffp;	if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {		xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",		      MCDX,		      stuffp->wreg_data, stuffp->irq, stuffp->irq);		stuffp->irq = 0;		kfree(stuffp);		return 0;	}	request_region((unsigned int) stuffp->wreg_data,		       MCDX_IO_SIZE,		       "mcdx");	xtrace(INIT, "init() get garbage\n");	{		int i;		mcdx_delay(stuffp, HZ/2);		for (i = 100; i; i--)			(void) inb((unsigned int) stuffp->rreg_status);	}#if WE_KNOW_WHY	/* irq 11 -> channel register */	outb(0x50, (unsigned int) stuffp->wreg_chn);#endif	xtrace(INIT, "init() set non dma but irq mode\n");	mcdx_config(stuffp, 1);	stuffp->minor = drive;	sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."		" (Firmware version %c %x)\n", 		stuffp->wreg_data, stuffp->irq, version.code,		version.ver);	mcdx_stuffp[drive] = stuffp;	xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);	mcdx_info.dev = MKDEV(MAJOR_NR,0);        if (register_cdrom(&mcdx_info) != 0) {		printk("Cannot register Mitsumi CD-ROM!\n");		release_region((unsigned long) stuffp->wreg_data,			       MCDX_IO_SIZE);		free_irq(stuffp->irq, NULL);		kfree(stuffp);		if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)        		xwarn("cleanup() unregister_blkdev() failed\n");		return 2;        }        printk(msg);	return 0;}__initfunc(int mcdx_init(void)){	int drive;#ifdef MODULE	xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");#else	xwarn("Version 2.14(hs) \n");#endif	xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");	/* zero the pointer array */	for (drive = 0; drive < MCDX_NDRIVES; drive++)		mcdx_stuffp[drive] = NULL;	/* do the initialisation */	for (drive = 0; drive < MCDX_NDRIVES; drive++) {		switch(mcdx_init_drive(drive)) {		case 2:			return -EIO;		case 1:			break;		}	}	return 0;}static intmcdx_transfer(struct s_drive_stuff *stuffp,		char *p, int sector, int nr_sectors)/*	This seems to do the actually transfer.  But it does more.  It	keeps track of errors occurred and will (if possible) fall back	to single speed on error.	Return:	-1 on timeout or other error			else status byte (as in stuff->st) */{	int ans;	ans = mcdx_xfer(stuffp, p, sector, nr_sectors);	return ans;#if FALLBACK	if (-1 == ans) stuffp->readerrs++;	else return ans;	if (stuffp->readerrs && stuffp->readcmd == READ1X) {		xwarn("XXX Already reading 1x -- no chance\n");		return -1;	}	xwarn("XXX Fallback to 1x\n");	stuffp->readcmd = READ1X;	return mcdx_transfer(stuffp, p, sector, nr_sectors);#endif}static int mcdx_xfer(struct s_drive_stuff *stuffp,		char *p, int sector, int nr_sectors)/*	This does actually the transfer from the drive.	Return:	-1 on timeout or other error			else status byte (as in stuff->st) */{    int border;    int done = 0;	long timeout;	if (stuffp->audio) {			xwarn("Attempt to read from audio CD.\n");			return -1;	}	if (!stuffp->readcmd) {			xinfo("Can't transfer from missing disk.\n");			return -1;	}    while (stuffp->lock) {		interruptible_sleep_on(&stuffp->lockq);	}    if (stuffp->valid			&& (sector >= stuffp->pending)			&& (sector < stuffp->low_border)) {		/* All (or at least a part of the sectors requested) seems         * to be already requested, so we don't need to bother the		 * drive with new requests ...		 * Wait for the drive become idle, but first		 * check for possible occurred errors --- the drive		 * seems to report them asynchronously */	border = stuffp->high_border < (border = sector + nr_sectors)			? stuffp->high_border : border;	stuffp->lock = current->pid;	do {	    while (stuffp->busy) {			timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ);			if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }			else if (!timeout) { xtrace(XFER, "timeout\n"); }			else if (signal_pending(current)) {				xtrace(XFER, "signal\n");			} else continue;			stuffp->lock = 0;			stuffp->busy = 0;			stuffp->valid = 0;			wake_up_interruptible(&stuffp->lockq);			xtrace(XFER, "transfer() done (-1)\n");			return -1;	    } 		/* check if we need to set the busy flag (as we		 * expect an interrupt */		stuffp->busy = (3 == (stuffp->pending & 3));		/* Test if it's the first sector of a block,		 * there we have to skip some bytes as we read raw data */		if (stuffp->xa && (0 == (stuffp->pending & 3))) {			const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;			insb((unsigned int) stuffp->rreg_data, p, HEAD);		}		/* now actually read the data */	    insb((unsigned int) stuffp->rreg_data, p, 512);		/* test if it's the last sector of a block,		 * if so, we have to handle XA special */		if ((3 == (stuffp->pending & 3)) && stuffp->xa) {			char dummy[CD_XA_TAIL];			insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);		}	    if (stuffp->pending == sector) {			p += 512;			done++;			sector++;	    }	} while (++(stuffp->pending) < border);	stuffp->lock = 0;	wake_up_interruptible(&stuffp->lockq);    } else {		/* The requested sector(s) is/are out of the		 * already requested range, so we have to bother the drive		 * with a new request. */		static unsigned char cmd[] = {			0,			0, 0, 0,			0, 0, 0		};		cmd[0] = stuffp->readcmd;		/* The numbers held in ->pending, ..., should be valid */		stuffp->valid = 1;		stuffp->pending = sector & ~3;		/* do some sanity checks */		if (stuffp->pending > stuffp->lastsector) {			xwarn("transfer() sector %d from nirvana requested.\n",				stuffp->pending);			stuffp->status = MCDX_ST_EOM;			stuffp->valid = 0;			xtrace(XFER, "transfer() done (-1)\n");			return -1;		}		if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)				> stuffp->lastsector + 1) {			xtrace(XFER, "cut low_border\n");			stuffp->low_border = stuffp->lastsector + 1;		}

⌨️ 快捷键说明

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