diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/sbus/char/sunmouse.c | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/sbus/char/sunmouse.c')
-rw-r--r-- | drivers/sbus/char/sunmouse.c | 127 |
1 files changed, 82 insertions, 45 deletions
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index f1641a33a..03869c52a 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -48,6 +48,7 @@ #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/poll.h> +#include <linux/spinlock.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -69,13 +70,13 @@ struct sun_mouse { unsigned char prev_state; /* Previous button state */ int delta_x; /* Current delta-x */ int delta_y; /* Current delta-y */ - int ready; /* set if there if data is available */ int active; /* set if device is open */ int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ wait_queue_head_t proc_list; struct fasync_struct *fasync; /* The event/stream queue */ + spinlock_t lock; unsigned int head; unsigned int tail; union { @@ -96,14 +97,22 @@ extern void mouse_put_char(char ch); static int push_event (Firm_event *ev) { - int next = (sunmouse.head + 1) % EV_SIZE; + unsigned long flags; + int next, ret; - if (next != sunmouse.tail){ + spin_lock_irqsave(&sunmouse.lock, flags); + + next = (sunmouse.head + 1) % EV_SIZE; + ret = 0; + if (next != sunmouse.tail) { sunmouse.queue.ev [sunmouse.head] = *ev; sunmouse.head = next; - return 1; + ret = 1; } - return 0; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + + return ret; } static int @@ -112,29 +121,32 @@ queue_empty (void) return sunmouse.head == sunmouse.tail; } -static Firm_event * -get_from_queue (void) +/* Must be invoked under the sunmouse.lock */ +static void get_from_queue (Firm_event *p) { - Firm_event *result; - - result = &sunmouse.queue.ev [sunmouse.tail]; + *p = sunmouse.queue.ev [sunmouse.tail]; sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE; - return result; } static void push_char (char c) { - int next = (sunmouse.head + 1) % STREAM_SIZE; + unsigned long flags; + int next; + + spin_lock_irqsave(&sunmouse.lock, flags); - if (next != sunmouse.tail){ + next = (sunmouse.head + 1) % STREAM_SIZE; + if (next != sunmouse.tail) { #ifdef SMOUSE_DEBUG printk("P<%02x>\n", (unsigned char)c); #endif sunmouse.queue.stream [sunmouse.head] = c; sunmouse.head = next; } - sunmouse.ready = 1; + + spin_unlock_irqrestore(&sunmouse.lock, flags); + if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible (&sunmouse.proc_list); @@ -325,24 +337,26 @@ sun_mouse_inbyte(unsigned char byte, int is_break) sunmouse.byte = 69; /* What could cause this? */ return; }; - if (!gen_events){ + + if (!gen_events) { push_char (~sunmouse.button_state & 0x87); push_char (sunmouse.delta_x); push_char (sunmouse.delta_y); return; } + d = bstate ^ pstate; pstate = bstate; - if (d){ - if (d & BUTTON_LEFT){ + if (d) { + if (d & BUTTON_LEFT) { ev.id = MS_LEFT; ev.value = bstate & BUTTON_LEFT; } - if (d & BUTTON_RIGHT){ + if (d & BUTTON_RIGHT) { ev.id = MS_RIGHT; ev.value = bstate & BUTTON_RIGHT; } - if (d & BUTTON_MIDDLE){ + if (d & BUTTON_MIDDLE) { ev.id = MS_MIDDLE; ev.value = bstate & BUTTON_MIDDLE; } @@ -350,25 +364,24 @@ sun_mouse_inbyte(unsigned char byte, int is_break) ev.value = ev.value ? VKEY_DOWN : VKEY_UP; pushed += push_event (&ev); } - if (sunmouse.delta_x){ + if (sunmouse.delta_x) { ev.id = LOC_X_DELTA; ev.time = xtime; ev.value = sunmouse.delta_x; pushed += push_event (&ev); sunmouse.delta_x = 0; } - if (sunmouse.delta_y){ + if (sunmouse.delta_y) { ev.id = LOC_Y_DELTA; ev.time = xtime; ev.value = sunmouse.delta_y; pushed += push_event (&ev); } - if(pushed != 0) { + if (pushed != 0) { /* We just completed a transaction, wake up whoever is awaiting * this event. */ - sunmouse.ready = 1; if (sunmouse.fasync) kill_fasync (sunmouse.fasync, SIGIO, POLL_IN); wake_up_interruptible(&sunmouse.proc_list); @@ -379,9 +392,9 @@ sun_mouse_inbyte(unsigned char byte, int is_break) static int sun_mouse_open(struct inode * inode, struct file * file) { - if(sunmouse.active++) + if (sunmouse.active++) return 0; - sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0; + sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.vuid_mode = VUID_NATIVE; return 0; @@ -401,9 +414,7 @@ static int sun_mouse_close(struct inode *inode, struct file *file) { sun_mouse_fasync (-1, file, 0); - if (--sunmouse.active) - return 0; - sunmouse.ready = 0; + sunmouse.active--; return 0; } @@ -419,49 +430,57 @@ sun_mouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); + unsigned long flags; - if (queue_empty ()){ + if (queue_empty ()) { if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&sunmouse.proc_list, &wait); - while (queue_empty () && !signal_pending(current)) { - current->state = TASK_INTERRUPTIBLE; - schedule (); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; } current->state = TASK_RUNNING; remove_wait_queue (&sunmouse.proc_list, &wait); } - if (gen_events){ + if (gen_events) { char *p = buffer, *end = buffer+count; + spin_lock_irqsave(&sunmouse.lock, flags); while (p < end && !queue_empty ()){ + Firm_event this_event; + + get_from_queue(&this_event); + spin_unlock_irqrestore(&sunmouse.lock, flags); + #ifdef CONFIG_SPARC32_COMPAT if (current->thread.flags & SPARC_FLAG_32BIT) { - Firm_event *q = get_from_queue(); - if ((end - p) < ((sizeof(Firm_event) - sizeof(struct timeval) + (sizeof(u32) * 2)))) break; - copy_to_user_ret((Firm_event *)p, q, + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event)-sizeof(struct timeval), -EFAULT); p += sizeof(Firm_event)-sizeof(struct timeval); - __put_user_ret(q->time.tv_sec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_sec, (u32 *)p, -EFAULT); p += sizeof(u32); - __put_user_ret(q->time.tv_usec, (u32 *)p, -EFAULT); + __put_user_ret(this_event.time.tv_usec, (u32 *)p, -EFAULT); p += sizeof(u32); } else #endif { if ((end - p) < sizeof(Firm_event)) break; - copy_to_user_ret((Firm_event *)p, get_from_queue(), + copy_to_user_ret((Firm_event *)p, &this_event, sizeof(Firm_event), -EFAULT); p += sizeof (Firm_event); } + spin_lock_irqsave(&sunmouse.lock, flags); } - sunmouse.ready = !queue_empty (); + spin_unlock_irqrestore(&sunmouse.lock, flags); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return p-buffer; } else { @@ -470,9 +489,24 @@ sun_mouse_read(struct file *file, char *buffer, if (count < limit) limit = count; for (c = 0; c < limit; c++) { - put_user(sunmouse.queue.stream[sunmouse.tail], buffer); + unsigned char val; + int empty = 0; + + spin_lock_irqsave(&sunmouse.lock, flags); + if (queue_empty()) { + empty = 1; + val = 0; + } else { + val = sunmouse.queue.stream[sunmouse.tail]; + sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; + } + spin_unlock_irqrestore(&sunmouse.lock, flags); + + if (empty) + break; + + put_user(val, buffer); buffer++; - sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; } while (c < count) { if (c >= 5) @@ -481,7 +515,6 @@ sun_mouse_read(struct file *file, char *buffer, buffer++; c++; } - sunmouse.ready = !queue_empty(); file->f_dentry->d_inode->i_atime = CURRENT_TIME; return c; } @@ -494,7 +527,7 @@ sun_mouse_read(struct file *file, char *buffer, static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { poll_wait(file, &sunmouse.proc_list, wait); - if(sunmouse.ready) + if(!queue_empty()) return POLLIN | POLLRDNORM; return 0; } @@ -516,8 +549,11 @@ sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsig int value; get_user_ret(value, (int *)arg, -EFAULT); + + spin_lock_irq(&sunmouse.lock); sunmouse.vuid_mode = value; sunmouse.head = sunmouse.tail = 0; + spin_unlock_irq(&sunmouse.lock); } else return -EINVAL; break; @@ -556,10 +592,11 @@ void sun_mouse_zsinit(void) { printk("Sun Mouse-Systems mouse driver version 1.00\n"); - sunmouse.ready = sunmouse.active = 0; + sunmouse.active = 0; misc_register (&sun_mouse_mouse); sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; init_waitqueue_head(&sunmouse.proc_list); + spin_lock_init(&sunmouse.lock); sunmouse.byte = 69; } |