patch-2.2.4 linux/drivers/macintosh/via-pmu.c
Next file: linux/drivers/misc/parport_ax.c
Previous file: linux/drivers/macintosh/macserial.h
Back to the patch index
Back to the overall index
- Lines: 459
- Date:
Wed Mar 10 21:48:46 1999
- Orig file:
v2.2.3/linux/drivers/macintosh/via-pmu.c
- Orig date:
Mon Dec 28 15:00:52 1998
diff -u --recursive --new-file v2.2.3/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
@@ -31,6 +31,7 @@
#include <asm/init.h>
#include <asm/irq.h>
#include <asm/feature.h>
+#include <asm/uaccess.h>
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
@@ -89,8 +90,9 @@
static 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;
+static struct adb_request bright_req_1, bright_req_2, bright_req_3;
static struct device_node *vias;
+static int pmu_kind = PMU_UNKNOWN;
int asleep;
struct notifier_block *sleep_notifier_list;
@@ -108,7 +110,6 @@
static void pmu_done(struct adb_request *req);
static void pmu_handle_data(unsigned char *data, int len,
struct pt_regs *regs);
-static void set_brightness(int level);
static void set_volume(int level);
/*
@@ -118,7 +119,7 @@
* - the number of response bytes which the PMU will return, or
* -1 if it will send a length byte.
*/
-static s8 pmu_data_len[256][2] = {
+static s8 pmu_data_len[256][2] __openfirmwaredata = {
/* 0 1 2 3 4 5 6 7 */
/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
@@ -154,9 +155,8 @@
/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
};
-__openfirmware
-void
+void __openfirmware
find_via_pmu()
{
vias = find_devices("via-pmu");
@@ -185,6 +185,15 @@
if (vias->n_addrs < 1 || vias->n_intrs < 1)
return;
}
+
+ if (vias->parent->name && strcmp(vias->parent->name, "ohare") == 0
+ || device_is_compatible(vias->parent, "ohare"))
+ pmu_kind = PMU_OHARE_BASED;
+ else if (device_is_compatible(vias->parent, "heathrow"))
+ pmu_kind = PMU_HEATHROW_BASED;
+ else
+ pmu_kind = PMU_UNKNOWN;
+
via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
@@ -195,9 +204,15 @@
via = NULL;
adb_hardware = ADB_VIAPMU;
+
+ if (via)
+ printk(KERN_INFO "PMU driver initialized for %s\n",
+ (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
+ ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
+ "Unknown PowerBook"));
}
-void
+void __openfirmware
via_pmu_init(void)
{
if (vias == NULL)
@@ -205,6 +220,7 @@
bright_req_1.complete = 1;
bright_req_2.complete = 1;
+ bright_req_3.complete = 1;
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
(void *)0)) {
@@ -220,9 +236,12 @@
adb_send_request = pmu_adb_send_request;
adb_autopoll = pmu_adb_autopoll;
adb_reset_bus = pmu_reset_bus;
+
+ /* Enable backlight */
+ pmu_enable_backlight(1);
}
-static int
+static int __openfirmware
init_pmu()
{
int timeout;
@@ -232,7 +251,7 @@
out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff);
- timeout = 100000;
+ timeout = 100000;
while (!req.complete) {
if (--timeout < 0) {
printk(KERN_ERR "init_pmu: no response from PMU\n");
@@ -259,8 +278,14 @@
return 1;
}
+int
+pmu_get_model(void)
+{
+ return pmu_kind;
+}
+
/* Send an ADB command */
-static int
+static int __openfirmware
pmu_adb_send_request(struct adb_request *req, int sync)
{
int i;
@@ -285,7 +310,7 @@
}
/* Enable/disable autopolling */
-static int
+static int __openfirmware
pmu_adb_autopoll(int devs)
{
struct adb_request req;
@@ -305,7 +330,7 @@
}
/* Reset the ADB bus */
-static int
+static int __openfirmware
pmu_reset_bus(void)
{
struct adb_request req;
@@ -348,7 +373,7 @@
}
/* Construct and send a pmu request */
-int
+int __openfirmware
pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
int nbytes, ...)
{
@@ -380,7 +405,7 @@
* first byte is CUDA_PACKET or PMU_PACKET. For CUDA_PACKET, we
* emulate a few CUDA requests.
*/
-int
+int __openfirmware
pmu_send_request(struct adb_request *req)
{
int i;
@@ -426,7 +451,7 @@
return -EINVAL;
}
-int
+int __openfirmware
pmu_queue_request(struct adb_request *req)
{
unsigned long flags;
@@ -465,7 +490,7 @@
return 0;
}
-static void
+static void __openfirmware
send_byte(int x)
{
out_8(&via[ACR], 0x1c);
@@ -473,7 +498,7 @@
out_8(&via[B], via[B] & ~0x10); /* assert TREQ */
}
-static void
+static void __openfirmware
recv_byte()
{
out_8(&via[ACR], 0x0c);
@@ -481,7 +506,7 @@
out_8(&via[B], via[B] & ~0x10);
}
-static void
+static void __openfirmware
pmu_start()
{
unsigned long flags;
@@ -506,7 +531,7 @@
restore_flags(flags);
}
-void
+void __openfirmware
pmu_poll()
{
int ie;
@@ -517,7 +542,7 @@
_enable_interrupts(ie);
}
-static void
+static void __openfirmware
via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
{
int intr;
@@ -553,7 +578,7 @@
}
}
-static void
+static void __openfirmware
pmu_sr_intr(struct pt_regs *regs)
{
struct adb_request *req;
@@ -649,7 +674,7 @@
}
}
-static void
+static void __openfirmware
pmu_done(struct adb_request *req)
{
req->complete = 1;
@@ -658,7 +683,7 @@
}
/* Interrupt data could be the result data from an ADB cmd */
-static void
+static void __openfirmware
pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
{
static int show_pmu_ints = 1;
@@ -689,7 +714,7 @@
} else {
if (data[0] == 0x08 && len == 3) {
/* sound/brightness buttons pressed */
- set_brightness(data[1]);
+ pmu_set_brightness(data[1] >> 3);
set_volume(data[2]);
} else if (show_pmu_ints
&& !(data[0] == PMU_INT_TICK && len == 1)) {
@@ -702,54 +727,101 @@
}
}
-int backlight_bright = -1;
+int backlight_level = -1;
int backlight_enabled = 0;
-#define LEVEL_TO_BRIGHT(lev) ((lev) < 8? 0x7f: 0x4a - ((lev) >> 2))
+#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
-void
+void __openfirmware
pmu_enable_backlight(int on)
{
struct adb_request req;
+ if (adb_hardware != ADB_VIAPMU)
+ return ;
+
if (on) {
- if (backlight_bright < 0) {
+ /* first call: get current backlight value */
+ if (backlight_level < 0) {
+ switch(pmu_kind) {
+ case PMU_OHARE_BASED:
pmu_request(&req, NULL, 2, 0xd9, 0);
while (!req.complete)
pmu_poll();
- backlight_bright = LEVEL_TO_BRIGHT(req.reply[1]);
+ backlight_level = req.reply[1] >> 3;
+ printk(KERN_DEBUG "pmu: controls returned bright: %d\n", (int)req.reply[1]);
+ break;
+ case PMU_HEATHROW_BASED:
+ pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
+ while (!req.complete)
+ pmu_poll();
+ printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
+ backlight_level = req.reply[1];
+ break;
+ default:
+ backlight_enabled = 0;
+ return;
}
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_bright);
- while (!req.complete)
- pmu_poll();
+ }
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ LEVEL_TO_BRIGHT(backlight_level));
+ while (!req.complete)
+ pmu_poll();
}
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_CTRL, on? 0x81: 1);
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
while (!req.complete)
pmu_poll();
backlight_enabled = on;
}
-static void
-set_brightness(int level)
+void __openfirmware
+pmu_set_brightness(int level)
{
- backlight_bright = LEVEL_TO_BRIGHT(level);
+ int bright;
+
+ if (adb_hardware != ADB_VIAPMU)
+ return ;
+
+ backlight_level = level;
+ bright = LEVEL_TO_BRIGHT(level);
if (!backlight_enabled)
return;
if (bright_req_1.complete)
pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_bright);
+ bright);
if (bright_req_2.complete)
- pmu_request(&bright_req_2, NULL, 2, PMU_BACKLIGHT_CTRL,
- backlight_bright < 0x7f? 0x81: 1);
+ pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
+
+ /* XXX nvram address is hard-coded and looks ok on wallstreet, please
+ test on your machine. Note that newer MacOS system software may break
+ the nvram layout. */
+ if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete)
+ pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM,
+ 0x14, 0xe, level);
}
-static void
+void __openfirmware
+pmu_enable_irled(int on)
+{
+ struct adb_request req;
+
+ if (adb_hardware != ADB_VIAPMU)
+ 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 __openfirmware
set_volume(int level)
{
}
-void
+void __openfirmware
pmu_restart(void)
{
struct adb_request req;
@@ -768,7 +840,7 @@
;
}
-void
+void __openfirmware
pmu_shutdown(void)
{
struct adb_request req;
@@ -802,7 +874,7 @@
} *pbook_pci_saves;
static int n_pbook_pci_saves;
-static inline void
+static inline void __openfirmware
pbook_pci_save(void)
{
int npci;
@@ -829,7 +901,7 @@
}
}
-static inline void
+static inline void __openfirmware
pbook_pci_restore(void)
{
u16 cmd;
@@ -868,7 +940,7 @@
#define IRQ_ENABLE ((unsigned int *)0xf3000024)
#define MEM_CTRL ((unsigned int *)0xf8000070)
-int powerbook_sleep(void)
+int __openfirmware powerbook_sleep(void)
{
int ret, i, x;
static int save_backlight;
@@ -967,29 +1039,44 @@
/*
* Support for /dev/pmu device
*/
-static int pmu_open(struct inode *inode, struct file *file)
+static int __openfirmware pmu_open(struct inode *inode, struct file *file)
{
return 0;
}
-static ssize_t pmu_read(struct file *file, char *buf,
+static ssize_t __openfirmware pmu_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
return 0;
}
-static ssize_t pmu_write(struct file *file, const char *buf,
+static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
return 0;
}
-static int pmu_ioctl(struct inode * inode, struct file *filp,
+/* Note: removed __openfirmware here since it causes link errors */
+static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
+ int error;
+ __u32 value;
+
switch (cmd) {
- case PMU_IOC_SLEEP:
+ case PMU_IOC_SLEEP:
+ if (pmu_kind != PMU_OHARE_BASED)
+ return -ENOSYS;
return powerbook_sleep();
+ case PMU_IOC_GET_BACKLIGHT:
+ return put_user(backlight_level, (__u32 *)arg);
+ case PMU_IOC_SET_BACKLIGHT:
+ error = get_user(value, (__u32 *)arg);
+ if (!error)
+ pmu_set_brightness(value);
+ return error;
+ case PMU_IOC_GET_MODEL:
+ return put_user(pmu_kind, (__u32 *)arg);
}
return -EINVAL;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)