patch-2.4.10 linux/drivers/macintosh/via-pmu.c
Next file: linux/drivers/md/Config.in
Previous file: linux/drivers/macintosh/rtc.c
Back to the patch index
Back to the overall index
- Lines: 811
- Date:
Sat Sep 8 12:38:42 2001
- Orig file:
v2.4.9/linux/drivers/macintosh/via-pmu.c
- Orig date:
Tue Jul 3 17:08:19 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
@@ -32,24 +32,30 @@
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <linux/smp_lock.h>
+#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <asm/init.h>
+#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/hardirq.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
+#include <asm/cputable.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
/* Some compile options */
#undef SUSPEND_USES_PMU
+#define DEBUG_SLEEP
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
@@ -102,13 +108,11 @@
static struct adb_request *current_req;
static struct adb_request *last_req;
static struct adb_request *req_awaiting_reply;
-static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */
+static unsigned char interrupt_data[32];
static unsigned char *reply_ptr;
static int data_index;
static int data_len;
static volatile int adb_int_pending;
-static int pmu_adb_flags;
-static int adb_dev_map = 0;
static struct adb_request bright_req_1, bright_req_2, bright_req_3;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
@@ -118,11 +122,20 @@
static int gpio_irq = -1;
static volatile int pmu_suspended = 0;
static spinlock_t pmu_lock;
+static u8 pmu_intr_mask;
+static int pmu_version;
+static int drop_interrupts;
+#ifdef CONFIG_PMAC_PBOOK
+static int sleep_in_progress;
+#endif /* CONFIG_PMAC_PBOOK */
int asleep;
struct notifier_block *sleep_notifier_list;
#ifdef CONFIG_ADB
+static int adb_dev_map = 0;
+static int pmu_adb_flags;
+
static int pmu_probe(void);
static int pmu_init(void);
static int pmu_send_request(struct adb_request *req, int sync);
@@ -163,8 +176,25 @@
#endif /* CONFIG_ADB */
extern void low_sleep_handler(void);
-extern void sleep_save_intrs(int);
-extern void sleep_restore_intrs(void);
+extern void pmac_sleep_save_intrs(int);
+extern void pmac_sleep_restore_intrs(void);
+extern void openpic_sleep_save_intrs(void);
+extern void openpic_sleep_restore_intrs(void);
+extern void enable_kernel_altivec(void);
+extern void enable_kernel_fp(void);
+
+#ifdef DEBUG_SLEEP
+int pmu_polled_request(struct adb_request *req);
+int pmu_wink(struct adb_request *req);
+#endif
+
+#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM)
+static int generic_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier generic_sleep_notifier = {
+ generic_notify_sleep,
+ SLEEP_LEVEL_MISC,
+};
+#endif /* defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM) */
/*
* This table indicates for each PMU opcode:
@@ -246,6 +276,11 @@
pmu_has_adb = 1;
+ pmu_intr_mask = PMU_INT_PCEJECT |
+ PMU_INT_SNDBRT |
+ PMU_INT_ADB |
+ PMU_INT_TICK;
+
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
|| device_is_compatible(vias->parent, "ohare")))
pmu_kind = PMU_OHARE_BASED;
@@ -258,7 +293,12 @@
pmu_kind = PMU_KEYLARGO_BASED;
pmu_has_adb = (find_type_devices("adb") != NULL);
-
+ pmu_intr_mask = PMU_INT_PCEJECT |
+ PMU_INT_SNDBRT |
+ PMU_INT_ADB |
+ PMU_INT_TICK |
+ PMU_INT_ENVIRONMENT;
+
gpiop = find_devices("gpio");
if (gpiop && gpiop->n_addrs) {
gpio_reg = ioremap(gpiop->addrs->address, 0x10);
@@ -281,11 +321,16 @@
return 0;
}
- printk(KERN_INFO "PMU driver initialized for %s\n",
- pbook_type[pmu_kind]);
+ printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
+ PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
sys_ctrler = SYS_CTRLER_PMU;
+#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM)
+ pmu_register_sleep_notifier(&generic_sleep_notifier);
+ pm_active = 1;
+#endif
+
return 1;
}
@@ -367,7 +412,7 @@
out_8(&via[B], via[B] | TREQ); /* negate TREQ */
out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
timeout = 100000;
while (!req.complete) {
if (--timeout < 0) {
@@ -392,13 +437,20 @@
udelay(10);
}
- /* Tell PMU we are ready. Which PMU support this ? */
+ /* Tell PMU we are ready. */
if (pmu_kind == PMU_KEYLARGO_BASED) {
pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
while (!req.complete)
pmu_poll();
}
-
+
+ /* Read PMU version */
+ pmu_request(&req, NULL, 1, PMU_GET_VERSION);
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len > 1)
+ pmu_version = req.reply[1];
+
return 1;
}
@@ -529,7 +581,7 @@
req.done = NULL;
req.data[0] = PMU_ADB_CMD;
req.data[1] = 0;
- req.data[2] = ADB_BUSRESET; /* 3 ??? */
+ req.data[2] = ADB_BUSRESET;
req.data[3] = 0;
req.data[4] = 0;
req.reply_len = 0;
@@ -759,7 +811,7 @@
}
adb_int_pending = 1;
#ifdef SUSPEND_USES_PMU
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
spin_unlock_irqrestore(&pmu_lock, flags);
while(!req.complete)
pmu_poll();
@@ -789,16 +841,11 @@
"intr=%x pmu_state=%d\n", intr, pmu_state);
break;
}
+ out_8(&via[IFR], intr);
if (intr & SR_INT)
pmu_sr_intr(regs);
- else if (intr & CB1_INT) {
+ else if (intr & CB1_INT)
adb_int_pending = 1;
- out_8(&via[IFR], CB1_INT);
- }
- intr &= ~(SR_INT | CB1_INT);
- if (intr != 0) {
- out_8(&via[IFR], intr);
- }
}
/* This is not necessary except if synchronous ADB requests are done
* with interrupts off, which should not happen. Since I'm not sure
@@ -846,23 +893,17 @@
out_8(&via[IFR], SR_INT);
return;
}
- /* This one seems to appear with PMU99. According to OF methods,
- * the protocol didn't change...
- */
- if (via[B] & TACK) {
- while ((in_8(&via[B]) & TACK) != 0)
+ /* The ack may not yet be low when we get the interrupt */
+ while ((in_8(&via[B]) & TACK) != 0)
;
- }
-
- /* reset TREQ and wait for TACK to go high */
- out_8(&via[B], in_8(&via[B]) | TREQ);
- wait_for_ack();
/* if reading grab the byte, and reset the interrupt */
if (pmu_state == reading || pmu_state == reading_intr)
bite = in_8(&via[SR]);
- out_8(&via[IFR], SR_INT);
+ /* reset TREQ and wait for TACK to go high */
+ out_8(&via[B], in_8(&via[B]) | TREQ);
+ wait_for_ack();
switch (pmu_state) {
case sending:
@@ -909,9 +950,8 @@
if (data_len == -1) {
data_len = bite;
if (bite > 32)
- printk(KERN_ERR "PMU: bad reply len %d\n",
- bite);
- } else {
+ printk(KERN_ERR "PMU: bad reply len %d\n", bite);
+ } else if (data_index < 32) {
reply_ptr[data_index++] = bite;
}
if (data_index < data_len) {
@@ -954,11 +994,14 @@
pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
{
asleep = 0;
- if (len < 1) {
-// xmon_printk("empty ADB\n");
+ if (drop_interrupts || len < 1) {
adb_int_pending = 0;
return;
}
+ /* Note: for some reason, we get an interrupt with len=1,
+ * data[0]==0 after each normal ADB interrupt, at least
+ * on the Pismo. Still investigating... --BenH
+ */
if (data[0] & PMU_INT_ADB) {
if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
struct adb_request *req = req_awaiting_reply;
@@ -1085,10 +1128,14 @@
cli();
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
- PMU_INT_TICK );
- while(!req.complete)
- pmu_poll();
+ 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);
while(!req.complete || (pmu_state != idle))
@@ -1104,10 +1151,14 @@
cli();
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
- PMU_INT_TICK );
- while(!req.complete)
- pmu_poll();
+ 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, 5, PMU_SHUTDOWN,
'M', 'A', 'T', 'T');
@@ -1127,6 +1178,22 @@
static LIST_HEAD(sleep_notifiers);
+#ifdef CONFIG_PM
+static int
+generic_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ if (pm_send_all(PM_SUSPEND, (void *)3))
+ return PBOOK_SLEEP_REJECT;
+ break;
+ case PBOOK_WAKE:
+ (void) pm_send_all(PM_RESUME, (void *)0);
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PM */
+
int
pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
{
@@ -1268,23 +1335,42 @@
}
}
-#if 0
+#ifdef DEBUG_SLEEP
/* N.B. This doesn't work on the 3400 */
-void pmu_blink(int n)
+void
+pmu_blink(int n)
{
struct adb_request req;
+ memset(&req, 0, sizeof(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);
+ 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);
}
- udelay(150000);
+ mdelay(50);
}
-#endif
+#endif /* DEBUG_SLEEP */
/*
* Put the powerbook to sleep.
@@ -1317,7 +1403,6 @@
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)
@@ -1363,7 +1448,8 @@
mb();
/* Wait for completion of async backlight requests */
- while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+ 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... */
@@ -1375,8 +1461,8 @@
while (!req.complete)
pmu_poll();
- /* Disable all interrupts except pmu */
- sleep_save_intrs(vias->intrs[0].line);
+ /* Disable all interrupts */
+ pmac_sleep_save_intrs(-1);
/* Make sure the PMU is idle */
while (pmu_state != idle)
@@ -1393,6 +1479,9 @@
if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
giveup_fpu(current);
+ /* We can now disable MSR_EE */
+ cli();
+
/* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
if (save_l2cr)
@@ -1431,7 +1520,7 @@
_set_L2CR(save_l2cr);
/* Restore userland MMU context */
- set_context(current->mm->context);
+ set_context(current->active_mm->context, current->active_mm->pgd);
/* Re-enable DEC interrupts and kick DEC */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
@@ -1464,26 +1553,29 @@
}
/* reenable interrupt controller */
- sleep_restore_intrs();
+ pmac_sleep_restore_intrs();
/* Leave some time for HW to settle down */
mdelay(100);
/* Notify drivers */
- 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;
-
+ int ret, timeout;
+
+ if (!feature_can_sleep()) {
+ printk(KERN_ERR "Sleep mode not supported on this machine\n");
+ return -ENOSYS;
+ }
+
/* Notify device drivers */
ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
if (ret != PBOOK_SLEEP_OK) {
@@ -1507,89 +1599,157 @@
}
/* Give the disks a little time to actually finish writing */
- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ for (wait = jiffies + HZ; 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();
+
/* 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);
+ /* Save & disable all interrupts */
+ openpic_sleep_save_intrs();
+
+ /* 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));
- /* Save the state of PCI config space for some slots */
- pbook_pci_save();
+ /* Giveup the FPU & vec */
+ enable_kernel_fp();
- feature_prepare_for_sleep();
+#ifdef CONFIG_ALTIVEC
+ if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+ enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+ /* We can now disable MSR_EE */
+ cli();
/* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
if (save_l2cr)
- _set_L2CR(0);
+ _set_L2CR(save_l2cr & 0x7fffffff);
- if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
- giveup_fpu(current);
+ /* Save the state of PCI config space for some slots */
+ //pbook_pci_save();
/* 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)
+ while (!req.complete && pmu_state != idle)
pmu_poll();
- /* Call low-level ASM sleep handler */
- low_sleep_handler();
+ out_8(&via[B], in_8(&via[B]) | TREQ);
+ wait_for_ack();
- /* Make sure the PMU is idle */
- while (pmu_state != idle)
- pmu_poll();
+ /* The VIA is supposed not to be restored correctly*/
+ save_via_state();
- sti();
+ /* 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.
+ */
+ feature_prepare_for_sleep();
+ /* Call low-level ASM sleep handler */
+ low_sleep_handler();
+
+ /* Restore Apple core ASICs state */
feature_wake_up();
- pbook_pci_restore();
- set_context(current->mm->context);
+ /* 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 | 0x200000); /* set invalidate bit */
+ _set_L2CR(save_l2cr);
+
+ /* Restore userland MMU context */
+ set_context(current->active_mm->context, current->active_mm->pgd);
- /* reenable interrupts */
- sleep_restore_intrs();
+ /* Re-enable DEC interrupts and kick DEC */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ sti();
+ asm volatile("mtdec %0" : : "r" (0x10000000));
/* 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);
+
/* Notify drivers */
- mdelay(10);
broadcast_wake();
return 0;
}
-#define PB3400_MEM_CTRL ((unsigned int *)0xf8000070)
+#define PB3400_MEM_CTRL 0xf8000000
+#define PB3400_MEM_CTRL_SLEEP 0x70
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;
+ 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);
@@ -1617,11 +1777,20 @@
for (wait = jiffies + (HZ/4); 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();
+
/* Disable all interrupts except pmu */
- sleep_save_intrs(vias->intrs[0].line);
+ 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();
@@ -1629,9 +1798,9 @@
/* 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);
+ out_be32(mem_ctrl_sleep, i);
do {
- x = (in_be32(PB3400_MEM_CTRL) >> 16) & 0x3ff;
+ x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;
} while (x == 0);
if (x >= 0x100)
break;
@@ -1651,32 +1820,36 @@
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);
+ _nmask_and_or_msr(0, MSR_POW | MSR_EE);
udelay(10);
/* OK, we're awake again, start restoring things */
- out_be32(PB3400_MEM_CTRL, 0x3f);
+ out_be32(mem_ctrl_sleep, 0x3f);
pbook_pci_restore();
/* wait for the PMU interrupt sequence to complete */
while (asleep)
mb();
+ /* Re-enable DEC interrupts and kick DEC */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ sti();
+ asm volatile("mtdec %0" : : "r" (0x10000000));
+
/* reenable interrupts */
- sleep_restore_intrs();
+ pmac_sleep_restore_intrs();
/* Notify drivers */
broadcast_wake();
+ iounmap(mem_ctrl);
return 0;
}
/*
* Support for /dev/pmu device
*/
-#define RB_SIZE 10
+#define RB_SIZE 0x10
struct pmu_private {
struct list_head list;
int rb_get;
@@ -1830,6 +2003,11 @@
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();
@@ -1838,20 +2016,24 @@
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;
}
+ sleep_in_progress = 0;
return error;
+ case PMU_IOC_CAN_SLEEP:
+ return put_user(feature_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;
@@ -1859,6 +2041,8 @@
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);
@@ -1893,7 +2077,7 @@
}
#endif /* CONFIG_PMAC_PBOOK */
-#if 0
+#ifdef DEBUG_SLEEP
static inline void polled_handshake(volatile unsigned char *via)
{
via[B] &= ~TREQ; eieio();
@@ -1939,6 +2123,8 @@
while (pmu_state != idle)
pmu_poll();
+ while ((via[B] & TACK) == 0)
+ ;
polled_send_byte(v, c);
if (l < 0) {
l = req->nbytes - 1;
@@ -1959,4 +2145,15 @@
restore_flags(flags);
return 0;
}
-#endif /* 0 */
+#endif /* DEBUG_SLEEP */
+
+EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_poll);
+EXPORT_SYMBOL(pmu_suspend);
+EXPORT_SYMBOL(pmu_resume);
+#ifdef CONFIG_PMAC_PBOOK
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
+EXPORT_SYMBOL(pmu_enable_irled);
+#endif /* CONFIG_PMAC_PBOOK */
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)