summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char/sunmouse.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
commitb9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch)
tree42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/sbus/char/sunmouse.c
parent7406b0a326f2d70ade2671c37d1beef62249db97 (diff)
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/sbus/char/sunmouse.c')
-rw-r--r--drivers/sbus/char/sunmouse.c127
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;
}