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

📄 via-pmu.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		} else {#ifdef CONFIG_XMON			if (len == 4 && data[1] == 0x2c) {				extern int xmon_wants_key, xmon_adb_keycode;				if (xmon_wants_key) {					xmon_adb_keycode = data[2];					return;				}			}#endif /* CONFIG_XMON */#ifdef CONFIG_ADB			/*			 * XXX On the [23]400 the PMU gives us an up			 * event for keycodes 0x74 or 0x75 when the PC			 * card eject buttons are released, so we			 * ignore those events.			 */			if (!(pmu_kind == PMU_OHARE_BASED && len == 4			      && data[1] == 0x2c && data[3] == 0xff			      && (data[2] & ~1) == 0xf4))				adb_input(data+1, len-1, regs, 1);#endif /* CONFIG_ADB */				}	} else if (data[0] == 0x08 && len == 3) {		/* sound/brightness buttons pressed */#ifdef CONFIG_PMAC_BACKLIGHT		set_backlight_level(data[1] >> 4);#endif		set_volume(data[2]);	} else {#ifdef CONFIG_PMAC_PBOOK		pmu_pass_intr(data, len);#endif	}}#ifdef CONFIG_PMAC_BACKLIGHTstatic int backlight_to_bright[] = {	0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,	0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e}; static int __openfirmwarepmu_set_backlight_enable(int on, int level, void* data){	struct adb_request req;		if (vias == NULL)		return -ENODEV;	if (on) {		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,			    backlight_to_bright[level]);		while (!req.complete)			pmu_poll();	}	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,		    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));	while (!req.complete)		pmu_poll();	return 0;}static int __openfirmwarepmu_set_backlight_level(int level, void* data){	if (vias == NULL)		return -ENODEV;	if (!bright_req_1.complete)		return -EAGAIN;	pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,		backlight_to_bright[level]);	if (!bright_req_2.complete)		return -EAGAIN;	pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT		| (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF));	return 0;}#endif /* CONFIG_PMAC_BACKLIGHT */void __openfirmwarepmu_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));	while (!req.complete)		pmu_poll();}static void __openfirmwareset_volume(int level){}void __openfirmwarepmu_restart(void){	struct adb_request req;	cli();	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);	while(!req.complete || (pmu_state != idle))		pmu_poll();	for (;;)		;}void __openfirmwarepmu_shutdown(void){	struct adb_request req;	cli();	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |					PMU_INT_TICK );	while(!req.complete)		pmu_poll();	pmu_request(&req, NULL, 5, PMU_SHUTDOWN,		    'M', 'A', 'T', 'T');	while(!req.complete || (pmu_state != idle))		pmu_poll();	for (;;)		;}intpmu_present(void){	return via != 0;}#ifdef CONFIG_PMAC_PBOOKstatic 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;}intpmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n){	if (n->list.next == 0)		return -ENOENT;	list_del(&n->list);	n->list.next = 0;	return 0;}/* Sleep is broadcast last-to-first */static intbroadcast_sleep(int when, int fallback){	int ret = PBOOK_SLEEP_OK;	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);		ret = notifier->notifier_call(notifier, when);		if (ret != PBOOK_SLEEP_OK) {			printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",			       when, notifier, notifier->notifier_call);			for (; list != &sleep_notifiers; list = list->next) {				notifier = list_entry(list, struct pmu_sleep_notifier, list);				notifier->notifier_call(notifier, fallback);			}			return ret;		}	}	return ret;}/* Wake is broadcast first-to-last */static intbroadcast_wake(void){	int ret = PBOOK_SLEEP_OK;	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);	}	return ret;}/* * This struct is used to store config register values for * PCI devices which may get powered off when we sleep. */static struct pci_save {	u16	command;	u16	cache_lat;	u16	intr;	u32	rom_address;} *pbook_pci_saves;static int n_pbook_pci_saves;static void __openfirmwarepbook_pci_save(void){	int npci;	struct pci_dev *pd;	struct pci_save *ps;	npci = 0;	pci_for_each_dev(pd) {		++npci;	}	n_pbook_pci_saves = npci;	if (npci == 0)		return;	ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);	pbook_pci_saves = ps;	if (ps == NULL)		return;	pci_for_each_dev(pd) {		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);		++ps;	}}static void __openfirmwarepbook_pci_restore(void){	u16 cmd;	struct pci_save *ps = pbook_pci_saves - 1;	struct pci_dev *pd;	int j;	pci_for_each_dev(pd) {		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;			/* other header types not restored at present */		}	}}#if 0/* N.B. This doesn't work on the 3400 */void pmu_blink(int n){	struct adb_request req;	for (; n > 0; --n) {		pmu_request(&req, NULL, 4, 0xee, 4, 0, 1);		while (!req.complete) pmu_poll();		udelay(50000);		pmu_request(&req, NULL, 4, 0xee, 4, 0, 0);		while (!req.complete) pmu_poll();		udelay(50000);	}	udelay(150000);}#endif/* * Put the powerbook to sleep. */ static u32 save_via[8];static void save_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 void restore_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);}#define FEATURE_CTRL(base)	((unsigned int *)(base + 0x38))#define	GRACKLE_PM	(1<<7)#define GRACKLE_DOZE	(1<<5)#define	GRACKLE_NAP	(1<<4)#define	GRACKLE_SLEEP	(1<<3)int __openfirmware powerbook_sleep_G3(void){	unsigned long save_l2cr;	unsigned long wait;	unsigned short pmcr1;	struct adb_request req;	int ret, timeout;	/* Notify device drivers */	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);	if (ret != PBOOK_SLEEP_OK) {		printk("pmu: sleep rejected\n");		return -EBUSY;	}	/* Sync the disks. */	/* XXX It would be nice to have some way to ensure that	 * nobody is dirtying any new buffers while we wait.	 * BenH: Moved to _after_ sleep request and changed video	 * drivers to vmalloc() during sleep request. This way, all	 * vmalloc's are done before actual sleep of block drivers */	fsync_dev(0);	/* Sleep can fail now. May not be very robust but useful for debugging */	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);	if (ret != PBOOK_SLEEP_OK) {		printk("pmu: sleep failed\n");		return -EBUSY;	}	/* Give the disks a little time to actually finish writing */	for (wait = jiffies + (HZ/2); time_before(jiffies, wait); )		mb();	/* Wait for completion of async backlight requests */	while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)		pmu_poll();		/* Turn off various things. Darwin does some retry tests here... */	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);	while (!req.complete)		pmu_poll();	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,		PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);	while (!req.complete)		pmu_poll();	/* Disable all interrupts except pmu */	sleep_save_intrs(vias->intrs[0].line);	/* Make sure the PMU is idle */	while (pmu_state != idle)		pmu_poll();	/* Make sure the decrementer won't interrupt us */	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* Make sure any pending DEC interrupt occuring while we did	 * the above didn't re-enable the DEC */	mb();	asm volatile("mtdec %0" : : "r" (0x7fffffff));		/* Giveup the FPU */	if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)		giveup_fpu(current);	/* For 750, save backside cache setting and disable it */	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */	if (save_l2cr)		_set_L2CR(0);	/* Ask the PMU to put us to sleep */	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');	while (!req.complete)		pmu_poll();	/* The VIA is supposed not to be restored correctly*/	save_via_state();	/* We shut down some HW */	feature_prepare_for_sleep();	grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);	/* Apparently, MacOS uses NAP mode for Grackle ??? */	pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); 	pmcr1 |= GRACKLE_PM|GRACKLE_NAP;	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);	/* Call low-level ASM sleep handler */	low_sleep_handler();	/* We're awake again, stop grackle PM */	grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);		/* Restore things */	feature_wake_up();	restore_via_state();		/* Restore L2 cache */	if (save_l2cr) 		_set_L2CR(save_l2cr);		/* Restore userland MMU context */	set_context(current->mm->context, current->mm->pgd);	/* Re-enable DEC interrupts and kick DEC */	asm volatile("mtdec %0" : : "r" (0x7fffffff));	sti();	asm volatile("mtdec %0" : : "r" (0x10000000));	/* Power things up */	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);	while (!req.complete)		pmu_poll();	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,			PMU_POW0_ON|PMU_POW0_HARD_DRIVE);	while (!req.complete)		pmu_poll();	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,			PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);	while (!req.complete)		pmu_poll();	/* ack all pending interrupts */	timeout = 100000;	interrupt_data[0] = 1;	while (interrupt_data[0] || pmu_state != idle) {		if (--timeout < 0)			break;		if (pmu_state == idle)			adb_int_pending = 1;		via_pmu_interrupt(0, 0, 0);		udelay(10);	}	/* reenable interrupt controller */	sleep_restore_intrs();	/* Leave some time for HW to settle down */	mdelay(100);	/* Notify drivers */

⌨️ 快捷键说明

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