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

📄 via-pmu.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	--disable_poll;	spin_unlock_irqrestore(&pmu_lock, flags);	/* Deal with completed PMU requests outside of the lock */	if (req) {		pmu_done(req);		req = NULL;	}			/* Deal with interrupt datas outside of the lock */	if (int_data >= 0) {		pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]);		spin_lock_irqsave(&pmu_lock, flags);		++disable_poll;		int_data_state[int_data] = int_data_empty;		int_data = -1;		goto recheck;	}	return IRQ_RETVAL(handled);}voidpmu_unlock(void){	unsigned long flags;	spin_lock_irqsave(&pmu_lock, flags);	if (pmu_state == locked)		pmu_state = idle;	adb_int_pending = 1;	spin_unlock_irqrestore(&pmu_lock, flags);}static irqreturn_tgpio1_interrupt(int irq, void *arg){	unsigned long flags;	if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {		spin_lock_irqsave(&pmu_lock, flags);		if (gpio_irq_enabled > 0) {			disable_irq_nosync(gpio_irq);			gpio_irq_enabled = 0;		}		pmu_irq_stats[1]++;		adb_int_pending = 1;		spin_unlock_irqrestore(&pmu_lock, flags);		via_pmu_interrupt(0, NULL);		return IRQ_HANDLED;	}	return IRQ_NONE;}voidpmu_enable_irled(int on){	struct adb_request req;	if (vias == NULL)		return ;	if (pmu_kind == PMU_KEYLARGO_BASED)		return ;	pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |	    (on ? PMU_POW_ON : PMU_POW_OFF));	pmu_wait_complete(&req);}voidpmu_restart(void){	struct adb_request req;	if (via == NULL)		return;	local_irq_disable();	drop_interrupts = 1;		if (pmu_kind != PMU_KEYLARGO_BASED) {		pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |						PMU_INT_TICK );		while(!req.complete)			pmu_poll();	}	pmu_request(&req, NULL, 1, PMU_RESET);	pmu_wait_complete(&req);	for (;;)		;}voidpmu_shutdown(void){	struct adb_request req;	if (via == NULL)		return;	local_irq_disable();	drop_interrupts = 1;	if (pmu_kind != PMU_KEYLARGO_BASED) {		pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |						PMU_INT_TICK );		pmu_wait_complete(&req);	} else {		/* Disable server mode on shutdown or we'll just		 * wake up again		 */		pmu_set_server_mode(0);	}	pmu_request(&req, NULL, 5, PMU_SHUTDOWN,		    'M', 'A', 'T', 'T');	pmu_wait_complete(&req);	for (;;)		;}intpmu_present(void){	return via != 0;}#ifdef CONFIG_PM_SLEEPstatic LIST_HEAD(sleep_notifiers);intpmu_register_sleep_notifier(struct pmu_sleep_notifier *n){	struct list_head *list;	struct pmu_sleep_notifier *notifier;	for (list = sleep_notifiers.next; list != &sleep_notifiers;	     list = list->next) {		notifier = list_entry(list, struct pmu_sleep_notifier, list);		if (n->priority > notifier->priority)			break;	}	__list_add(&n->list, list->prev, list);	return 0;}EXPORT_SYMBOL(pmu_register_sleep_notifier);intpmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n){	if (n->list.next == 0)		return -ENOENT;	list_del(&n->list);	n->list.next = NULL;	return 0;}EXPORT_SYMBOL(pmu_unregister_sleep_notifier);#endif /* CONFIG_PM_SLEEP */#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)/* Sleep is broadcast last-to-first */static void broadcast_sleep(int when){	struct list_head *list;	struct pmu_sleep_notifier *notifier;	for (list = sleep_notifiers.prev; list != &sleep_notifiers;	     list = list->prev) {		notifier = list_entry(list, struct pmu_sleep_notifier, list);		notifier->notifier_call(notifier, when);	}}/* Wake is broadcast first-to-last */static void broadcast_wake(void){	struct list_head *list;	struct pmu_sleep_notifier *notifier;	for (list = sleep_notifiers.next; list != &sleep_notifiers;	     list = list->next) {		notifier = list_entry(list, struct pmu_sleep_notifier, list);		notifier->notifier_call(notifier, PBOOK_WAKE);	}}/* * This struct is used to store config register values for * PCI devices which may get powered off when we sleep. */static struct pci_save {#ifndef HACKED_PCI_SAVE	u16	command;	u16	cache_lat;	u16	intr;	u32	rom_address;#else	u32	config[16];#endif	} *pbook_pci_saves;static int pbook_npci_saves;static voidpbook_alloc_pci_save(void){	int npci;	struct pci_dev *pd = NULL;	npci = 0;	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {		++npci;	}	if (npci == 0)		return;	pbook_pci_saves = (struct pci_save *)		kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);	pbook_npci_saves = npci;}static voidpbook_free_pci_save(void){	if (pbook_pci_saves == NULL)		return;	kfree(pbook_pci_saves);	pbook_pci_saves = NULL;	pbook_npci_saves = 0;}static voidpbook_pci_save(void){	struct pci_save *ps = pbook_pci_saves;	struct pci_dev *pd = NULL;	int npci = pbook_npci_saves;		if (ps == NULL)		return;	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {		if (npci-- == 0) {			pci_dev_put(pd);			return;		}#ifndef HACKED_PCI_SAVE		pci_read_config_word(pd, PCI_COMMAND, &ps->command);		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);		pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);#else		int i;		for (i=1;i<16;i++)			pci_read_config_dword(pd, i<<4, &ps->config[i]);#endif		++ps;	}}/* For this to work, we must take care of a few things: If gmac was enabled * during boot, it will be in the pci dev list. If it's disabled at this point * (and it will probably be), then you can't access it's config space. */static voidpbook_pci_restore(void){	u16 cmd;	struct pci_save *ps = pbook_pci_saves - 1;	struct pci_dev *pd = NULL;	int npci = pbook_npci_saves;	int j;	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {#ifdef HACKED_PCI_SAVE		int i;		if (npci-- == 0) {			pci_dev_put(pd);			return;		}		ps++;		for (i=2;i<16;i++)			pci_write_config_dword(pd, i<<4, ps->config[i]);		pci_write_config_dword(pd, 4, ps->config[1]);#else		if (npci-- == 0)			return;		ps++;		if (ps->command == 0)			continue;		pci_read_config_word(pd, PCI_COMMAND, &cmd);		if ((ps->command & ~cmd) == 0)			continue;		switch (pd->hdr_type) {		case PCI_HEADER_TYPE_NORMAL:			for (j = 0; j < 6; ++j)				pci_write_config_dword(pd,					PCI_BASE_ADDRESS_0 + j*4,					pd->resource[j].start);			pci_write_config_dword(pd, PCI_ROM_ADDRESS,				ps->rom_address);			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,				ps->cache_lat);			pci_write_config_word(pd, PCI_INTERRUPT_LINE,				ps->intr);			pci_write_config_word(pd, PCI_COMMAND, ps->command);			break;		}#endif		}}#ifdef DEBUG_SLEEP/* N.B. This doesn't work on the 3400 */void pmu_blink(int n){	struct adb_request req;	memset(&req, 0, sizeof(req));	for (; n > 0; --n) {		req.nbytes = 4;		req.done = NULL;		req.data[0] = 0xee;		req.data[1] = 4;		req.data[2] = 0;		req.data[3] = 1;		req.reply[0] = ADB_RET_OK;		req.reply_len = 1;		req.reply_expected = 0;		pmu_polled_request(&req);		mdelay(50);		req.nbytes = 4;		req.done = NULL;		req.data[0] = 0xee;		req.data[1] = 4;		req.data[2] = 0;		req.data[3] = 0;		req.reply[0] = ADB_RET_OK;		req.reply_len = 1;		req.reply_expected = 0;		pmu_polled_request(&req);		mdelay(50);	}	mdelay(50);}#endif/* * Put the powerbook to sleep. */ static u32 save_via[8];static voidsave_via_state(void){	save_via[0] = in_8(&via[ANH]);	save_via[1] = in_8(&via[DIRA]);	save_via[2] = in_8(&via[B]);	save_via[3] = in_8(&via[DIRB]);	save_via[4] = in_8(&via[PCR]);	save_via[5] = in_8(&via[ACR]);	save_via[6] = in_8(&via[T1CL]);	save_via[7] = in_8(&via[T1CH]);}static voidrestore_via_state(void){	out_8(&via[ANH], save_via[0]);	out_8(&via[DIRA], save_via[1]);	out_8(&via[B], save_via[2]);	out_8(&via[DIRB], save_via[3]);	out_8(&via[PCR], save_via[4]);	out_8(&via[ACR], save_via[5]);	out_8(&via[T1CL], save_via[6]);	out_8(&via[T1CH], save_via[7]);	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */	out_8(&via[IFR], 0x7f);				/* clear IFR */	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);}extern void pmu_backlight_set_sleep(int sleep);static intpmac_suspend_devices(void){	int ret;	pm_prepare_console();		/* Notify old-style device drivers */	broadcast_sleep(PBOOK_SLEEP_REQUEST);	/* Sync the disks. */	/* XXX It would be nice to have some way to ensure that	 * nobody is dirtying any new buffers while we wait. That	 * could be achieved using the refrigerator for processes	 * that swsusp uses	 */	sys_sync();	broadcast_sleep(PBOOK_SLEEP_NOW);	/* Send suspend call to devices, hold the device core's dpm_sem */	ret = device_suspend(PMSG_SUSPEND);	if (ret) {		broadcast_wake();		printk(KERN_ERR "Driver sleep failed\n");		return -EBUSY;	}#ifdef CONFIG_PMAC_BACKLIGHT	/* Tell backlight code not to muck around with the chip anymore */	pmu_backlight_set_sleep(1);#endif	/* Call platform functions marked "on sleep" */	pmac_pfunc_i2c_suspend();	pmac_pfunc_base_suspend();	/* Stop preemption */	preempt_disable();	/* Make sure the decrementer won't interrupt us */	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* Make sure any pending DEC interrupt occurring while we did	 * the above didn't re-enable the DEC */	mb();	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* We can now disable MSR_EE. This code of course works properly only	 * on UP machines... For SMP, if we ever implement sleep, we'll have to	 * stop the "other" CPUs way before we do all that stuff.	 */	local_irq_disable();	/* Broadcast power down irq	 * This isn't that useful in most cases (only directly wired devices can	 * use this but still... This will take care of sysdev's as well, so	 * we exit from here with local irqs disabled and PIC off.	 */	ret = device_power_down(PMSG_SUSPEND);	if (ret) {		wakeup_decrementer();		local_irq_enable();		preempt_enable();		device_resume();		broadcast_wake();		printk(KERN_ERR "Driver powerdown failed\n");		return -EBUSY;	}	/* Wait for completion of async requests */	while (!batt_req.complete)		pmu_poll();	/* Giveup the lazy FPU & vec so we don't have to back them	 * up from the low level code	 */	enable_kernel_fp();#ifdef CONFIG_ALTIVEC	if (cpu_has_feature(CPU_FTR_ALTIVEC))		enable_kernel_altivec();#endif /* CONFIG_ALTIVEC */	return 0;}static intpmac_wakeup_devices(void){	mdelay(100);#ifdef CONFIG_PMAC_BACKLIGHT	/* Tell backlight code it can use the chip again */	pmu_backlight_set_sleep(0);#endif	/* Power back up system devices (including the PIC) */	device_power_up();	/* Force a poll of ADB interrupts */	adb_int_pending = 1;	via_pmu_interrupt(0, NULL);	/* Restart jiffies & scheduling */	wakeup_decrementer();	/* Re-enable local CPU interrupts */	local_irq_enable();	mdelay(10);	preempt_enable();	/* Call platform functions marked "on wake" */	pmac_pfunc_base_resume();	pmac_pfunc_i2c_resume();	/* Resume devices */	device_resume();	/* Notify old style drivers */	broadcast_wake();	pm_restore_console();	return 0;}#define	GRACKLE_PM	(1<<7)#define GRACKLE_DOZE	(1<<5)#define	GRACKLE_NAP	(1<<4)#define	GRACKLE_SLEEP	(1<<3)static int powerbook_sleep_grackle(void){	unsigned long save_l2cr;	unsigned short pmcr1;	struct adb_request req;	int ret;	struct pci_dev *grackle;	grackle = pci_get_bus_and_slot(0, 0);	if (!grackle)		return -ENODEV;	ret = pmac_suspend_devices();	if (ret) {		printk(KERN_ERR "Sleep rejected by devices\n");

⌨️ 快捷键说明

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