patch-2.3.99-pre6 linux/drivers/sbus/char/sunmouse.c
Next file: linux/drivers/sbus/char/zs.c
Previous file: linux/drivers/sbus/char/sunkbd.c
Back to the patch index
Back to the overall index
- Lines: 315
- Date:
Mon Apr 24 13:59:58 2000
- Orig file:
v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c
- Orig date:
Mon Mar 27 08:08:27 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/sbus/char/sunmouse.c linux/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 @@
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 @@
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 @@
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;
- if (next != sunmouse.tail){
+ spin_lock_irqsave(&sunmouse.lock, flags);
+
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
buffer++;
c++;
}
- sunmouse.ready = !queue_empty();
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
return c;
}
@@ -494,7 +527,7 @@
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 @@
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 @@
{
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;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)