mediabay.c

来自「linux 内核源代码」· C语言 代码 · 共 850 行 · 第 1/2 页

C
850
字号
			media_bays[i].cd_index = -1;			return -EINVAL;		}#endif /* CONFIG_BLK_DEV_IDE */	return -ENODEV;}EXPORT_SYMBOL(check_media_bay);int check_media_bay_by_base(unsigned long base, int what){#ifdef CONFIG_BLK_DEV_IDE	int	i;	for (i=0; i<media_bay_count; i++)		if (media_bays[i].mdev && base == (unsigned long) media_bays[i].cd_base) {			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)				return 0;			media_bays[i].cd_index = -1;			return -EINVAL;		} #endif		return -ENODEV;}int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,	int irq, int index){#ifdef CONFIG_BLK_DEV_IDE	int	i;	for (i=0; i<media_bay_count; i++) {		struct media_bay_info* bay = &media_bays[i];		if (bay->mdev && which_bay == bay->mdev->ofdev.node) {			int timeout = 5000;						down(&bay->lock); 			bay->cd_base	= (void __iomem *) base;			bay->cd_irq	= irq;			if ((MB_CD != bay->content_id) || bay->state != mb_up) {				up(&bay->lock);				return 0;			}			printk(KERN_DEBUG "Registered ide%d for media bay %d\n", index, i);			do {				if (MB_IDE_READY(i)) {					bay->cd_index	= index;					up(&bay->lock);					return 0;				}				mdelay(1);			} while(--timeout);			printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);			up(&bay->lock);			return -ENODEV;		}	}#endif /* CONFIG_BLK_DEV_IDE */		return -ENODEV;}static void media_bay_step(int i){	struct media_bay_info* bay = &media_bays[i];	/* We don't poll when powering down */	if (bay->state != mb_powering_down)	    poll_media_bay(bay);	/* If timer expired or polling IDE busy, run state machine */	if ((bay->state != mb_ide_waiting) && (bay->timer != 0)) {		bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);		if (bay->timer > 0)			return;		bay->timer = 0;	}	switch(bay->state) {	case mb_powering_up:	    	if (bay->ops->setup_bus(bay, bay->last_value) < 0) {			MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id);	    		set_mb_power(bay, 0);	    		break;	    	}	    	bay->timer = msecs_to_jiffies(MB_RESET_DELAY);	    	bay->state = mb_enabling_bay;		MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);		break;	case mb_enabling_bay:		bay->ops->un_reset(bay);	    	bay->timer = msecs_to_jiffies(MB_SETUP_DELAY);	    	bay->state = mb_resetting;		MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);	    	break;	    	case mb_resetting:		if (bay->content_id != MB_CD) {			MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);			bay->state = mb_up;			break;	    	}#ifdef CONFIG_BLK_DEV_IDE		MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);		bay->ops->un_reset_ide(bay);	    	bay->timer = msecs_to_jiffies(MB_IDE_WAIT);	    	bay->state = mb_ide_resetting;#else		printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);		set_mb_power(bay, 0);#endif /* CONFIG_BLK_DEV_IDE */	    	break;	    #ifdef CONFIG_BLK_DEV_IDE	case mb_ide_resetting:	    	bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);	    	bay->state = mb_ide_waiting;		MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);	    	break;	    	case mb_ide_waiting:		if (bay->cd_base == NULL) {			bay->timer = 0;			bay->state = mb_up;			MBDBG("mediabay%d: up before IDE init\n", i);			break;		} else if (MB_IDE_READY(i)) {			bay->timer = 0;			bay->state = mb_up;			if (bay->cd_index < 0) {				hw_regs_t hw;				printk("mediabay %d, registering IDE...\n", i);				pmu_suspend();				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);				hw.irq = bay->cd_irq;				hw.chipset = ide_pmac;				bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);				pmu_resume();			}			if (bay->cd_index == -1) {				/* We eventually do a retry */				bay->cd_retry++;				printk("IDE register error\n");				set_mb_power(bay, 0);			} else {				printk(KERN_DEBUG "media-bay %d is ide%d\n", i, bay->cd_index);				MBDBG("mediabay %d IDE ready\n", i);			}			break;	    	} else if (bay->timer > 0)			bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);	    	if (bay->timer <= 0) {			printk("\nIDE Timeout in bay %d !, IDE state is: 0x%02x\n",			       i, readb(bay->cd_base + 0x70));			MBDBG("mediabay%d: nIDE Timeout !\n", i);			set_mb_power(bay, 0);			bay->timer = 0;	    	}		break;#endif /* CONFIG_BLK_DEV_IDE */	case mb_powering_down:	    	bay->state = mb_empty;#ifdef CONFIG_BLK_DEV_IDE    	        if (bay->cd_index >= 0) {			printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,			       bay->cd_index);			ide_unregister(bay->cd_index);			bay->cd_index = -1;		}	    	if (bay->cd_retry) {			if (bay->cd_retry > MAX_CD_RETRIES) {				/* Should add an error sound (sort of beep in dmasound) */				printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);			} else {				/* Force a new power down/up sequence */				bay->content_id = MB_NO;			}	    	}#endif /* CONFIG_BLK_DEV_IDE */    		MBDBG("mediabay%d: end of power down\n", i);	    	break;	}}/* * This procedure runs as a kernel thread to poll the media bay * once each tick and register and unregister the IDE interface * with the IDE driver.  It needs to be a thread because * ide_register can't be called from interrupt context. */static int media_bay_task(void *x){	int	i;	strcpy(current->comm, "media-bay");#ifdef MB_IGNORE_SIGNALS	sigfillset(&current->blocked);#endif	for (;;) {		for (i = 0; i < media_bay_count; ++i) {			down(&media_bays[i].lock);			if (!media_bays[i].sleeping)				media_bay_step(i);			up(&media_bays[i].lock);		}		msleep_interruptible(MB_POLL_DELAY);		if (signal_pending(current))			return 0;	}}static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match){	struct media_bay_info* bay;	u32 __iomem *regbase;	struct device_node *ofnode;	unsigned long base;	int i;	ofnode = mdev->ofdev.node;	if (macio_resource_count(mdev) < 1)		return -ENODEV;	if (macio_request_resources(mdev, "media-bay"))		return -EBUSY;	/* Media bay registers are located at the beginning of the         * mac-io chip, for now, we trick and align down the first	 * resource passed in         */	base = macio_resource_start(mdev, 0) & 0xffff0000u;	regbase = (u32 __iomem *)ioremap(base, 0x100);	if (regbase == NULL) {		macio_release_resources(mdev);		return -ENOMEM;	}		i = media_bay_count++;	bay = &media_bays[i];	bay->mdev = mdev;	bay->base = regbase;	bay->index = i;	bay->ops = match->data;	bay->sleeping = 0;	init_MUTEX(&bay->lock);	/* Init HW probing */	if (bay->ops->init)		bay->ops->init(bay);	printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", i, bay->ops->name);	/* Force an immediate detect */	set_mb_power(bay, 0);	msleep(MB_POWER_DELAY);	bay->content_id = MB_NO;	bay->last_value = bay->ops->content(bay);	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);	bay->state = mb_empty;	do {		msleep(MB_POLL_DELAY);		media_bay_step(i);	} while((bay->state != mb_empty) &&		(bay->state != mb_up));	/* Mark us ready by filling our mdev data */	macio_set_drvdata(mdev, bay);	/* Startup kernel thread */	if (i == 0)		kernel_thread(media_bay_task, NULL, CLONE_KERNEL);	return 0;}static int media_bay_suspend(struct macio_dev *mdev, pm_message_t state){	struct media_bay_info	*bay = macio_get_drvdata(mdev);	if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) {		down(&bay->lock);		bay->sleeping = 1;		set_mb_power(bay, 0);		up(&bay->lock);		msleep(MB_POLL_DELAY);		mdev->ofdev.dev.power.power_state = state;	}	return 0;}static int media_bay_resume(struct macio_dev *mdev){	struct media_bay_info	*bay = macio_get_drvdata(mdev);	if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {		mdev->ofdev.dev.power.power_state = PMSG_ON;	       	/* We re-enable the bay using it's previous content	       	   only if it did not change. Note those bozo timings,	       	   they seem to help the 3400 get it right.	       	 */	       	/* Force MB power to 0 */		down(&bay->lock);	       	set_mb_power(bay, 0);		msleep(MB_POWER_DELAY);	       	if (bay->ops->content(bay) != bay->content_id) {			printk("mediabay%d: content changed during sleep...\n", bay->index);			up(&bay->lock);	       		return 0;		}	       	set_mb_power(bay, 1);	       	bay->last_value = bay->content_id;	       	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);	       	bay->timer = msecs_to_jiffies(MB_POWER_DELAY);#ifdef CONFIG_BLK_DEV_IDE	       	bay->cd_retry = 0;#endif	       	do {			msleep(MB_POLL_DELAY);	       		media_bay_step(bay->index);	       	} while((bay->state != mb_empty) &&	       		(bay->state != mb_up));		bay->sleeping = 0;		up(&bay->lock);	}	return 0;}/* Definitions of "ops" structures. */static struct mb_ops ohare_mb_ops = {	.name		= "Ohare",	.content	= ohare_mb_content,	.power		= ohare_mb_power,	.setup_bus	= ohare_mb_setup_bus,	.un_reset	= ohare_mb_un_reset,	.un_reset_ide	= ohare_mb_un_reset_ide,};static struct mb_ops heathrow_mb_ops = {	.name		= "Heathrow",	.content	= heathrow_mb_content,	.power		= heathrow_mb_power,	.setup_bus	= heathrow_mb_setup_bus,	.un_reset	= heathrow_mb_un_reset,	.un_reset_ide	= heathrow_mb_un_reset_ide,};static struct mb_ops keylargo_mb_ops = {	.name		= "KeyLargo",	.init		= keylargo_mb_init,	.content	= keylargo_mb_content,	.power		= keylargo_mb_power,	.setup_bus	= keylargo_mb_setup_bus,	.un_reset	= keylargo_mb_un_reset,	.un_reset_ide	= keylargo_mb_un_reset_ide,};/* * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL * register is always set when there is something in the media bay. * This causes problems for the interrupt code if we attach an interrupt * handler to the media-bay interrupt, because it tends to go into * an infinite loop calling the media bay interrupt handler. * Therefore we do it all by polling the media bay once each tick. */static struct of_device_id media_bay_match[] ={	{	.name		= "media-bay",	.compatible	= "keylargo-media-bay",	.data		= &keylargo_mb_ops,	},	{	.name		= "media-bay",	.compatible	= "heathrow-media-bay",	.data		= &heathrow_mb_ops,	},	{	.name		= "media-bay",	.compatible	= "ohare-media-bay",	.data		= &ohare_mb_ops,	},	{},};static struct macio_driver media_bay_driver ={	.name		= "media-bay",	.match_table	= media_bay_match,	.probe		= media_bay_attach,	.suspend	= media_bay_suspend,	.resume		= media_bay_resume};static int __init media_bay_init(void){	int i;	for (i=0; i<MAX_BAYS; i++) {		memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));		media_bays[i].content_id	= -1;#ifdef CONFIG_BLK_DEV_IDE		media_bays[i].cd_index		= -1;#endif	}	if (!machine_is(powermac))		return 0;	macio_register_driver(&media_bay_driver);		return 0;}device_initcall(media_bay_init);

⌨️ 快捷键说明

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