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

📄 via-pmu.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Call low-level ASM sleep handler */	if (__fake_sleep)		mdelay(5000);	else		low_sleep_handler();	/* Restore Apple core ASICs state */	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);	/* Restore VIA */	restore_via_state();	/* Restore PCI config space. This should be overridable by PCI device	 * drivers as some of them may need special restore code. That's yet	 * another issue that should be handled by the common code properly,	 * maybe one day ?	 */	/* Don't restore PCI for now, it crashes. Maybe unnecessary on pbook */	//pbook_pci_restore();	pmu_blink(2);			/* Restore L2 cache */	if (save_l2cr) 		_set_L2CR(save_l2cr);		/* Restore userland MMU context */	set_context(current->active_mm->context, current->active_mm->pgd);	/* Tell PMU we are ready */	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);	while (!req.complete)		pmu_poll();	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);	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 */	openpic_sleep_restore_intrs();	/* Leave some time for HW to settle down */	mdelay(100);	/* Restart jiffies & scheduling */	wakeup_decrementer();	sti();	/* Notify drivers */	broadcast_wake();	return 0;}#define PB3400_MEM_CTRL		0xf8000000#define PB3400_MEM_CTRL_SLEEP	0x70int __openfirmware powerbook_sleep_3400(void){	int ret, i, x;	unsigned int hid0;	unsigned long p, wait;	struct adb_request sleep_req;	char *mem_ctrl;	unsigned int *mem_ctrl_sleep;	/* first map in the memory controller registers */	mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);	if (mem_ctrl == NULL) {		printk("powerbook_sleep_3400: ioremap failed\n");		return -ENOMEM;	}	mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP);	/* 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);	/* Give the disks a little time to actually finish writing */	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )		mb();	/* 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;	}	/* Wait for completion of async backlight requests */	while (!bright_req_1.complete || !bright_req_2.complete ||		!bright_req_3.complete || !batt_req.complete)		pmu_poll();	/* Disable all interrupts except pmu */	pmac_sleep_save_intrs(vias->intrs[0].line);	/* 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));	/* Save the state of PCI config space for some slots */	pbook_pci_save();	/* Set the memory controller to keep the memory refreshed	   while we're asleep */	for (i = 0x403f; i >= 0x4000; --i) {		out_be32(mem_ctrl_sleep, i);		do {			x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;		} while (x == 0);		if (x >= 0x100)			break;	}	/* Ask the PMU to put us to sleep */	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');	while (!sleep_req.complete)		mb();	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);	/* displacement-flush the L2 cache - necessary? */	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)		i = *(volatile int *)p;	asleep = 1;	/* Put the CPU into sleep mode */	asm volatile("mfspr %0,1008" : "=r" (hid0) :);	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;	asm volatile("mtspr 1008,%0" : : "r" (hid0));	_nmask_and_or_msr(0, MSR_POW | MSR_EE);	udelay(10);	/* OK, we're awake again, start restoring things */	out_be32(mem_ctrl_sleep, 0x3f);	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);	pbook_pci_restore();	/* wait for the PMU interrupt sequence to complete */	while (asleep)		mb();	/* reenable interrupts */	pmac_sleep_restore_intrs();	/* Leave some time for HW to settle down */	mdelay(100);	/* Restart jiffies & scheduling */	wakeup_decrementer();	sti();	/* Notify drivers */	broadcast_wake();	iounmap(mem_ctrl);	return 0;}/* * Support for /dev/pmu device */#define RB_SIZE		0x10struct pmu_private {	struct list_head list;	int	rb_get;	int	rb_put;	struct rb_entry {		unsigned short len;		unsigned char data[16];	}	rb_buf[RB_SIZE];	wait_queue_head_t wait;	spinlock_t lock;};static LIST_HEAD(all_pmu_pvt);static spinlock_t all_pvt_lock = SPIN_LOCK_UNLOCKED;static void pmu_pass_intr(unsigned char *data, int len){	struct pmu_private *pp;	struct list_head *list;	int i;	unsigned long flags;	if (len > sizeof(pp->rb_buf[0].data))		len = sizeof(pp->rb_buf[0].data);	spin_lock_irqsave(&all_pvt_lock, flags);	for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) {		pp = list_entry(list, struct pmu_private, list);		spin_lock(&pp->lock);		i = pp->rb_put + 1;		if (i >= RB_SIZE)			i = 0;		if (i != pp->rb_get) {			struct rb_entry *rp = &pp->rb_buf[pp->rb_put];			rp->len = len;			memcpy(rp->data, data, len);			pp->rb_put = i;			wake_up_interruptible(&pp->wait);		}		spin_unlock(&pp->lock);	}	spin_unlock_irqrestore(&all_pvt_lock, flags);}static int __openfirmware pmu_open(struct inode *inode, struct file *file){	struct pmu_private *pp;	unsigned long flags;	pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL);	if (pp == 0)		return -ENOMEM;	pp->rb_get = pp->rb_put = 0;	spin_lock_init(&pp->lock);	init_waitqueue_head(&pp->wait);	spin_lock_irqsave(&all_pvt_lock, flags);	list_add(&pp->list, &all_pmu_pvt);	spin_unlock_irqrestore(&all_pvt_lock, flags);	file->private_data = pp;	return 0;}static ssize_t __openfirmware pmu_read(struct file *file, char *buf,			size_t count, loff_t *ppos){	struct pmu_private *pp = file->private_data;	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	int ret;	if (count < 1 || pp == 0)		return -EINVAL;	ret = verify_area(VERIFY_WRITE, buf, count);	if (ret)		return ret;	spin_lock_irqsave(&pp->lock, flags);	add_wait_queue(&pp->wait, &wait);	current->state = TASK_INTERRUPTIBLE;	for (;;) {		ret = -EAGAIN;		if (pp->rb_get != pp->rb_put) {			int i = pp->rb_get;			struct rb_entry *rp = &pp->rb_buf[i];			ret = rp->len;			spin_unlock_irqrestore(&pp->lock, flags);			if (ret > count)				ret = count;			if (ret > 0 && copy_to_user(buf, rp->data, ret))				ret = -EFAULT;			if (++i >= RB_SIZE)				i = 0;			spin_lock_irqsave(&pp->lock, flags);			pp->rb_get = i;		}		if (ret >= 0)			break;		if (file->f_flags & O_NONBLOCK)			break;		ret = -ERESTARTSYS;		if (signal_pending(current))			break;		spin_unlock_irqrestore(&pp->lock, flags);		schedule();		spin_lock_irqsave(&pp->lock, flags);	}	current->state = TASK_RUNNING;	remove_wait_queue(&pp->wait, &wait);	spin_unlock_irqrestore(&pp->lock, flags);		return ret;}static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,			 size_t count, loff_t *ppos){	return 0;}static unsigned int pmu_fpoll(struct file *filp, poll_table *wait){	struct pmu_private *pp = filp->private_data;	unsigned int mask = 0;	unsigned long flags;		if (pp == 0)		return 0;	poll_wait(filp, &pp->wait, wait);	spin_lock_irqsave(&pp->lock, flags);	if (pp->rb_get != pp->rb_put)		mask |= POLLIN;	spin_unlock_irqrestore(&pp->lock, flags);	return mask;}static int pmu_release(struct inode *inode, struct file *file){	struct pmu_private *pp = file->private_data;	unsigned long flags;	lock_kernel();	if (pp != 0) {		file->private_data = 0;		spin_lock_irqsave(&all_pvt_lock, flags);		list_del(&pp->list);		spin_unlock_irqrestore(&all_pvt_lock, flags);		kfree(pp);	}	unlock_kernel();	return 0;}/* Note: removed __openfirmware here since it causes link errors */static int pmu_ioctl(struct inode * inode, struct file *filp,		     u_int cmd, u_long arg){	int error;	switch (cmd) {	case PMU_IOC_SLEEP:		if (!capable(CAP_SYS_ADMIN))			return -EACCES;		if (sleep_in_progress)			return -EBUSY;		sleep_in_progress = 1;		switch (pmu_kind) {		case PMU_OHARE_BASED:			error = powerbook_sleep_3400();			break;		case PMU_HEATHROW_BASED:		case PMU_PADDINGTON_BASED:			error = powerbook_sleep_G3();			break;		case PMU_KEYLARGO_BASED:			error = powerbook_sleep_Core99();			break;		default:			error = -ENOSYS;		}		sleep_in_progress = 0;		return error;	case PMU_IOC_CAN_SLEEP:		return put_user((u32)can_sleep, (__u32 *)arg);#ifdef CONFIG_PMAC_BACKLIGHT	/* Backlight should have its own device or go via	 * the fbdev	 */	case PMU_IOC_GET_BACKLIGHT:		if (sleep_in_progress)			return -EBUSY;		error = get_backlight_level();		if (error < 0)			return error;		return put_user(error, (__u32 *)arg);	case PMU_IOC_SET_BACKLIGHT:	{		__u32 value;		if (sleep_in_progress)			return -EBUSY;		error = get_user(value, (__u32 *)arg);		if (!error)			error = set_backlight_level(value);		return error;	}#endif /* CONFIG_PMAC_BACKLIGHT */	case PMU_IOC_GET_MODEL:	    	return put_user(pmu_kind, (__u32 *)arg);	case PMU_IOC_HAS_ADB:		return put_user(pmu_has_adb, (__u32 *)arg);	}	return -EINVAL;}static struct file_operations pmu_device_fops = {	read:		pmu_read,	write:		pmu_write,	poll:		pmu_fpoll,	ioctl:		pmu_ioctl,	open:		pmu_open,	release:	pmu_release,};static struct miscdevice pmu_device = {	PMU_MINOR, "pmu", &pmu_device_fops};void pmu_device_init(void){	if (via)		misc_register(&pmu_device);}#endif /* CONFIG_PMAC_PBOOK */#ifdef DEBUG_SLEEPstatic inline void polled_handshake(volatile unsigned char *via){	via[B] &= ~TREQ; eieio();	while ((via[B] & TACK) != 0)		;	via[B] |= TREQ; eieio();	while ((via[B] & TACK) == 0)		;}static inline void polled_send_byte(volatile unsigned char *via, int x){	via[ACR] |= SR_OUT | SR_EXT; eieio();	via[SR] = x; eieio();	polled_handshake(via);}static inline int polled_recv_byte(volatile unsigned char *via){	int x;	via[ACR] = (via[ACR] & ~SR_OUT) | SR_EXT; eieio();	x = via[SR]; eieio();	polled_handshake(via);	x = via[SR]; eieio();	return x;}intpmu_polled_request(struct adb_request *req){	unsigned long flags;	int i, l, c;	volatile unsigned char *v = via;	req->complete = 1;	c = req->data[0];	l = pmu_data_len[c][0];	if (l >= 0 && req->nbytes != l + 1)		return -EINVAL;	save_flags(flags); cli();	while (pmu_state != idle)		pmu_poll();	while ((via[B] & TACK) == 0)		;	polled_send_byte(v, c);	if (l < 0) {		l = req->nbytes - 1;		polled_send_byte(v, l);	}	for (i = 1; i <= l; ++i)		polled_send_byte(v, req->data[i]);	l = pmu_data_len[c][1];	if (l < 0)		l = polled_recv_byte(v);	for (i = 0; i < l; ++i)		req->reply[i + req->reply_len] = polled_recv_byte(v);	if (req->done)		(*req->done)(req);	restore_flags(flags);	return 0;}#endif /* DEBUG_SLEEP */EXPORT_SYMBOL(pmu_request);EXPORT_SYMBOL(pmu_poll);EXPORT_SYMBOL(pmu_suspend);EXPORT_SYMBOL(pmu_resume);#ifdef CONFIG_PMAC_PBOOKEXPORT_SYMBOL(pmu_register_sleep_notifier);EXPORT_SYMBOL(pmu_unregister_sleep_notifier);EXPORT_SYMBOL(pmu_enable_irled);EXPORT_SYMBOL(pmu_battery_count);EXPORT_SYMBOL(pmu_batteries);EXPORT_SYMBOL(pmu_power_flags);#endif /* CONFIG_PMAC_PBOOK */

⌨️ 快捷键说明

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