Commit 8631d753 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] adbhid preempt/smp races

This fixes a few races in the LED code of the adbhid driver that would
affect SMP or preempt.
parent 1c754472
...@@ -107,7 +107,6 @@ static struct adbhid *adbhid[16] = { 0 }; ...@@ -107,7 +107,6 @@ static struct adbhid *adbhid[16] = { 0 };
static void adbhid_probe(void); static void adbhid_probe(void);
static void adbhid_input_keycode(int, int, int, struct pt_regs *); static void adbhid_input_keycode(int, int, int, struct pt_regs *);
static void leds_done(struct adb_request *);
static void init_trackpad(int id); static void init_trackpad(int id);
static void init_trackball(int id); static void init_trackball(int id);
...@@ -446,16 +445,45 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto ...@@ -446,16 +445,45 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
static struct adb_request led_request; static struct adb_request led_request;
static int leds_pending[16]; static int leds_pending[16];
static int leds_req_pending;
static int pending_devs[16]; static int pending_devs[16];
static int pending_led_start=0; static int pending_led_start=0;
static int pending_led_end=0; static int pending_led_end=0;
static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
static void leds_done(struct adb_request *req)
{
int leds, device;
unsigned long flags;
spin_lock_irqsave(&leds_lock, flags);
if (pending_led_start != pending_led_end) {
device = pending_devs[pending_led_start];
leds = leds_pending[device] & 0xff;
leds_pending[device] = 0;
pending_led_start++;
pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
} else
leds_req_pending = 0;
spin_unlock_irqrestore(&leds_lock, flags);
if (leds_req_pending)
adb_request(&led_request, leds_done, 0, 3,
ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
}
static void real_leds(unsigned char leds, int device) static void real_leds(unsigned char leds, int device)
{ {
if (led_request.complete) { unsigned long flags;
spin_lock_irqsave(&leds_lock, flags);
if (!leds_req_pending) {
leds_req_pending = 1;
spin_unlock_irqrestore(&leds_lock, flags);
adb_request(&led_request, leds_done, 0, 3, adb_request(&led_request, leds_done, 0, 3,
ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
~leds); return;
} else { } else {
if (!(leds_pending[device] & 0x100)) { if (!(leds_pending[device] & 0x100)) {
pending_devs[pending_led_end] = device; pending_devs[pending_led_end] = device;
...@@ -464,6 +492,7 @@ static void real_leds(unsigned char leds, int device) ...@@ -464,6 +492,7 @@ static void real_leds(unsigned char leds, int device)
} }
leds_pending[device] = leds | 0x100; leds_pending[device] = leds | 0x100;
} }
spin_unlock_irqrestore(&leds_lock, flags);
} }
/* /*
...@@ -487,21 +516,6 @@ static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned i ...@@ -487,21 +516,6 @@ static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned i
return -1; return -1;
} }
static void leds_done(struct adb_request *req)
{
int leds,device;
if (pending_led_start != pending_led_end) {
device = pending_devs[pending_led_start];
leds = leds_pending[device] & 0xff;
leds_pending[device] = 0;
pending_led_start++;
pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
real_leds(leds,device);
}
}
static int static int
adb_message_handler(struct notifier_block *this, unsigned long code, void *x) adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
{ {
...@@ -518,7 +532,7 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) ...@@ -518,7 +532,7 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
} }
/* Stop pending led requests */ /* Stop pending led requests */
while(!led_request.complete) while(leds_req_pending)
adb_poll(); adb_poll();
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment