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

📄 via-pmu.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	mdelay(10);	broadcast_wake();	return 0;}/* Not finished yet */int __openfirmware powerbook_sleep_Core99(void){	int ret;	unsigned long save_l2cr;	unsigned long wait;	struct adb_request req;	/* 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/4); time_before(jiffies, wait); )		mb();	/* Tell PMU what events will wake us up */	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,		0xff, 0xff);	while (!req.complete)		pmu_poll();	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,		0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN);	while (!req.complete)		pmu_poll();			/* Disable all interrupts except pmu */	sleep_save_intrs(vias->intrs[0].line);	/* Make sure the decrementer won't interrupt us */	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* Save the state of PCI config space for some slots */	pbook_pci_save();	feature_prepare_for_sleep();	/* For 750, save backside cache setting and disable it */	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */	if (save_l2cr)		_set_L2CR(0);	if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)		giveup_fpu(current);	/* Ask the PMU to put us to sleep */	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');	while (!req.complete)		mb();	cli();	while (pmu_state != idle)		pmu_poll();	/* Call low-level ASM sleep handler */	low_sleep_handler();	/* Make sure the PMU is idle */	while (pmu_state != idle)		pmu_poll();	sti();	feature_wake_up();	pbook_pci_restore();	set_context(current->mm->context, current->mm->pgd);	/* Restore L2 cache */	if (save_l2cr) 		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */	/* reenable interrupts */	sleep_restore_intrs();	/* Tell PMU we are ready */	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);	while (!req.complete)		pmu_poll();			/* Notify drivers */	mdelay(10);	broadcast_wake();	return 0;}#define PB3400_MEM_CTRL		((unsigned int *)0xf8000070)int __openfirmware powerbook_sleep_3400(void){	int ret, i, x;	unsigned long msr;	unsigned int hid0;	unsigned long p, wait;	struct adb_request sleep_req;	/* 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/4); time_before(jiffies, wait); )		mb();	/* Disable all interrupts except pmu */	sleep_save_intrs(vias->intrs[0].line);	/* Make sure the decrementer won't interrupt us */	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(PB3400_MEM_CTRL, i);		do {			x = (in_be32(PB3400_MEM_CTRL) >> 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();	/* 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));	save_flags(msr);	msr |= MSR_POW | MSR_EE;	restore_flags(msr);	udelay(10);	/* OK, we're awake again, start restoring things */	out_be32(PB3400_MEM_CTRL, 0x3f);	pbook_pci_restore();	/* wait for the PMU interrupt sequence to complete */	while (asleep)		mb();	/* reenable interrupts */	sleep_restore_intrs();	/* Notify drivers */	broadcast_wake();	return 0;}/* * Support for /dev/pmu device */#define RB_SIZE		10struct 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);		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_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);	int ret;	if (count < 1 || pp == 0)		return -EINVAL;	ret = verify_area(VERIFY_WRITE, buf, count);	if (ret)		return ret;	add_wait_queue(&pp->wait, &wait);	current->state = TASK_INTERRUPTIBLE;	for (;;) {		ret = -EAGAIN;		spin_lock(&pp->lock);		if (pp->rb_get != pp->rb_put) {			int i = pp->rb_get;			struct rb_entry *rp = &pp->rb_buf[i];			ret = rp->len;			if (ret > count)				ret = count;			if (ret > 0 && copy_to_user(buf, rp->data, ret))				ret = -EFAULT;			if (++i >= RB_SIZE)				i = 0;			pp->rb_get = i;		}		spin_unlock(&pp->lock);		if (ret >= 0)			break;		if (file->f_flags & O_NONBLOCK)			break;		ret = -ERESTARTSYS;		if (signal_pending(current))			break;		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(&pp->wait, &wait);	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;	if (pp == 0)		return 0;	poll_wait(filp, &pp->wait, wait);	spin_lock(&pp->lock);	if (pp->rb_get != pp->rb_put)		mask |= POLLIN;	spin_unlock(&pp->lock);	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:		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;#if 0 /* Not ready yet */		case PMU_KEYLARGO_BASED:			error = powerbook_sleep_Core99();			break;#endif					default:			error = -ENOSYS;		}		return error;#ifdef CONFIG_PMAC_BACKLIGHT	/* Backlight should have its own device or go via	 * the fbdev	 */	case PMU_IOC_GET_BACKLIGHT:		error = get_backlight_level();		if (error < 0)			return error;		return put_user(error, (__u32 *)arg);	case PMU_IOC_SET_BACKLIGHT:	{		__u32 value;		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 */#if 0static 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();	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 /* 0 */

⌨️ 快捷键说明

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