📄 via-pmu.c
字号:
return ret; } /* 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); pmu_wait_complete(&req); pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY); pmu_wait_complete(&req); /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ if (!__fake_sleep) { /* Ask the PMU to put us to sleep */ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); pmu_wait_complete(&req); } /* The VIA is supposed not to be restored correctly*/ save_via_state(); /* We shut down some HW */ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); pci_read_config_word(grackle, 0x70, &pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); pmcr1 |= GRACKLE_PM|GRACKLE_NAP; pci_write_config_word(grackle, 0x70, pmcr1); /* Call low-level ASM sleep handler */ if (__fake_sleep) mdelay(5000); else low_sleep_handler(); /* We're awake again, stop grackle PM */ pci_read_config_word(grackle, 0x70, &pmcr1); pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); pci_write_config_word(grackle, 0x70, pmcr1); pci_dev_put(grackle); /* Make sure the PMU is idle */ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); /* Restore L2 cache */ if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) _set_L2CR(save_l2cr); /* Restore userland MMU context */ set_context(current->active_mm->context.id, current->active_mm->pgd); /* Power things up */ pmu_unlock(); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_wait_complete(&req); pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_ON|PMU_POW0_HARD_DRIVE); pmu_wait_complete(&req); pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); pmu_wait_complete(&req); pmac_wakeup_devices(); return 0;}static intpowerbook_sleep_Core99(void){ unsigned long save_l2cr; unsigned long save_l3cr; struct adb_request req; int ret; if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) { printk(KERN_ERR "Sleep mode not supported on this machine\n"); return -ENOSYS; } if (num_online_cpus() > 1 || cpu_is_offline(0)) return -EAGAIN; ret = pmac_suspend_devices(); if (ret) { printk(KERN_ERR "Sleep rejected by devices\n"); return ret; } /* Stop environment and ADB interrupts */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); pmu_wait_complete(&req); /* Tell PMU what events will wake us up */ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, 0xff, 0xff); pmu_wait_complete(&req); pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, 0, PMU_PWR_WAKEUP_KEY | (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0)); pmu_wait_complete(&req); /* Save the state of the L2 and L3 caches */ save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ if (!__fake_sleep) { /* Ask the PMU to put us to sleep */ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); pmu_wait_complete(&req); } /* The VIA is supposed not to be restored correctly*/ save_via_state(); /* Shut down various ASICs. There's a chance that we can no longer * talk to the PMU after this, so I moved it to _after_ sending the * sleep command to it. Still need to be checked. */ pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1); /* 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(); /* tweak LPJ before cpufreq is there */ loops_per_jiffy *= 2; /* Restore video */ pmac_call_early_video_resume(); /* Restore L2 cache */ if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) _set_L2CR(save_l2cr); /* Restore L3 cache */ if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) _set_L3CR(save_l3cr); /* Restore userland MMU context */ set_context(current->active_mm->context.id, current->active_mm->pgd); /* Tell PMU we are ready */ pmu_unlock(); pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); pmu_wait_complete(&req); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_wait_complete(&req); /* Restore LPJ, cpufreq will adjust the cpu frequency */ loops_per_jiffy /= 2; pmac_wakeup_devices(); return 0;}#define PB3400_MEM_CTRL 0xf8000000#define PB3400_MEM_CTRL_SLEEP 0x70static intpowerbook_sleep_3400(void){ int ret, i, x; unsigned int hid0; unsigned long p; struct adb_request sleep_req; void __iomem *mem_ctrl; unsigned int __iomem *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 = mem_ctrl + PB3400_MEM_CTRL_SLEEP; /* Allocate room for PCI save */ pbook_alloc_pci_save(); ret = pmac_suspend_devices(); if (ret) { pbook_free_pci_save(); iounmap(mem_ctrl); printk(KERN_ERR "Sleep rejected by devices\n"); return ret; } /* 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 */ hid0 = mfspr(SPRN_HID0); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; mtspr(SPRN_HID0, hid0); mtmsr(mfmsr() | 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(); pmu_unlock(); /* wait for the PMU interrupt sequence to complete */ while (asleep) mb(); pmac_wakeup_devices(); pbook_free_pci_save(); iounmap(mem_ctrl); return 0;}#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 *//* * 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;#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) int backlight_locker;#endif};static LIST_HEAD(all_pmu_pvt);static DEFINE_SPINLOCK(all_pvt_lock);static voidpmu_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 intpmu_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);#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) pp->backlight_locker = 0;#endif list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; return 0;}static ssize_t pmu_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ struct pmu_private *pp = file->private_data; DECLARE_WAITQUEUE(wait, current); unsigned long flags; int ret = 0; if (count < 1 || pp == 0) return -EINVAL; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; 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_tpmu_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ return 0;}static unsigned intpmu_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 intpmu_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 = NULL; spin_lock_irqsave(&all_pvt_lock, flags); list_del(&pp->list); spin_unlock_irqrestore(&all_pvt_lock, flags);#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) if (pp->backlight_locker) pmac_backlight_enable();#endif kfree(pp); } unlock_kernel(); return 0;}static intpmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg){ __u32 __user *argp = (__u32 __user *)arg; int error = -EINVAL; switch (cmd) {#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) 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_grackle(); break; case PMU_KEYLARGO_BASED: error = powerbook_sleep_Core99(); break; default: error = -ENOSYS; } sleep_in_progress = 0; break; case PMU_IOC_CAN_SLEEP: if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) return put_user(0, argp); else return put_user(1, argp);#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY /* Compatibility ioctl's for backlight */ case PMU_IOC_GET_BACKLIGHT: { int brightness; if (sleep_in_progress) return -EBUSY; brightness = pmac_backlight_get_legacy_brightness(); if (brightness < 0) return brightness; else return put_user(brightness, argp); } case PMU_IOC_SET_BACKLIGHT: { int brightness; if (sleep_in_progress) return -EBUSY; error = get_user(brightness, argp); if (error) return error; return pmac_backlight_set_legacy_brightness(brightness); }#ifdef CONFIG_INPUT_ADBHID case PMU_IOC_GRAB_BACKLIGHT: { struct pmu_private *pp = filp->private_data; if (pp->backlight_locker) return 0; pp->backlight_locker = 1; pmac_backlight_disable(); return 0; }#endif /* CONFIG_INPUT_ADBHID */#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */ case PMU_IOC_GET_MODEL: return put_user(pmu_kind, argp); case PMU_IOC_HAS_ADB: return put_user(pmu_has_adb, argp); } return error;}static const 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};static int pmu_device_init(void){ if (!via) return 0; if (misc_register(&pmu_device) < 0) printk(KERN_ERR "via-pmu: cannot register misc device.\n"); return 0;}device_i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -