patch-2.2.11 linux/drivers/macintosh/via-pmu.c
Next file: linux/drivers/misc/parport_pc.c
Previous file: linux/drivers/macintosh/mediabay.c
Back to the patch index
Back to the overall index
- Lines: 247
- Date:
Mon Aug 9 12:04:57 1999
- Orig file:
v2.2.10/linux/drivers/macintosh/via-pmu.c
- Orig date:
Thu Apr 29 12:53:48 1999
diff -u --recursive --new-file v2.2.10/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
@@ -21,6 +21,7 @@
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/malloc.h>
+#include <linux/poll.h>
#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/pmu.h>
@@ -112,6 +113,9 @@
static void pmu_handle_data(unsigned char *data, int len,
struct pt_regs *regs);
static void set_volume(int level);
+#ifdef CONFIG_PMAC_PBOOK
+static void pmu_pass_intr(unsigned char *data, int len);
+#endif
static struct adb_controller pmu_controller = {
ADB_VIAPMU,
@@ -729,21 +733,32 @@
}
pmu_done(req);
} else {
- adb_input(data+1, len-1, regs, 1);
+ /*
+ * XXX the PMU gives us an up event for keycodes
+ * 0x74 or 0x75 when the PC card eject buttons
+ * are released, so we ignore those events.
+ */
+ if (!(len == 4 && data[1] == 0x2c && data[3] == 0xff
+ && (data[2] & ~1) == 0xf4))
+ adb_input(data+1, len-1, regs, 1);
}
+ } else if (data[0] == 0x08 && len == 3) {
+ /* sound/brightness buttons pressed */
+ pmu_set_brightness(data[1] >> 3);
+ set_volume(data[2]);
} else {
- if (data[0] == 0x08 && len == 3) {
- /* sound/brightness buttons pressed */
- pmu_set_brightness(data[1] >> 3);
- set_volume(data[2]);
- } else if (show_pmu_ints
- && !(data[0] == PMU_INT_TICK && len == 1)) {
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_pass_intr(data, len);
+#else
+ if (show_pmu_ints
+ && !(data[0] == PMU_INT_TICK && len == 1)) {
int i;
printk(KERN_DEBUG "pmu intr");
for (i = 0; i < len; ++i)
printk(" %.2x", data[i]);
printk("\n");
}
+#endif
}
}
@@ -1064,15 +1079,112 @@
/*
* Support for /dev/pmu device
*/
+#define RB_SIZE 10
+struct 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];
+ struct wait_queue *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);
+ pp->wait = 0;
+ 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)
{
- return 0;
+ struct pmu_private *pp = file->private_data;
+ struct wait_queue wait = { current, NULL };
+ 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,
@@ -1081,6 +1193,36 @@
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;
+
+ 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);
+ }
+ return 0;
+}
+
/* 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)
@@ -1089,18 +1231,18 @@
__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:
+ case PMU_IOC_GET_BACKLIGHT:
return put_user(backlight_level, (__u32 *)arg);
- case PMU_IOC_SET_BACKLIGHT:
+ case PMU_IOC_SET_BACKLIGHT:
error = get_user(value, (__u32 *)arg);
if (!error)
pmu_set_brightness(value);
return error;
- case PMU_IOC_GET_MODEL:
+ case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, (__u32 *)arg);
}
return -EINVAL;
@@ -1111,12 +1253,12 @@
pmu_read,
pmu_write,
NULL, /* no readdir */
- NULL, /* no poll yet */
+ pmu_fpoll,
pmu_ioctl,
NULL, /* no mmap */
pmu_open,
NULL, /* flush */
- NULL /* no release */
+ pmu_release,
};
static struct miscdevice pmu_device = {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)