Commit 6dbb845a authored by James Lamanna's avatar James Lamanna Committed by Greg Kroah-Hartman

[PATCH] USB: Fix down() in hard IRQ in powermate driver

Fixes this warning:

May 18 06:56:01 Knoppix kernel: Debug: sleeping function called from
invalid context at include/asm/semaphore.h:119
May 18 06:56:01 Knoppix kernel: in_atomic():1, irqs_disabled():0
May 18 06:56:01 Knoppix kernel: Call Trace:
May 18 06:56:01 Knoppix kernel:  [<c0117083>] __might_sleep+0xb2/0xd3
May 18 06:56:01 Knoppix kernel:  [<f88b92f4>] powermate_config_complete+0x33/0x77 [powermate]
May 18 06:56:01 Knoppix kernel:  [<c02c6760>] usb_hcd_giveback_urb+0x25/0x39
May 18 06:56:01 Knoppix kernel:  [<c02d7194>] uhci_finish_urb+0x54/0xa1
May 18 06:56:01 Knoppix kernel:  [<c02d7224>] uhci_finish_completion+0x43/0x55
May 18 06:56:01 Knoppix kernel:  [<c02d737d>] uhci_irq+0xf8/0x179
May 18 06:56:01 Knoppix kernel:  [<c02c67aa>] usb_hcd_irq+0x36/0x67
May 18 06:56:01 Knoppix kernel:  [<c01060c6>] handle_IRQ_event+0x3a/0x64
May 18 06:56:01 Knoppix kernel:  [<c0106479>] do_IRQ+0xb8/0x192
May 18 06:56:01 Knoppix kernel:  [<c0104850>] common_interrupt+0x18/0x20

Attached patch uses spinlocks instead of a semaphore so that we can't sleep
when in_atomic().
parent 8639d2a4
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/usb.h> #include <linux/usb.h>
#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */
...@@ -67,7 +68,7 @@ struct powermate_device { ...@@ -67,7 +68,7 @@ struct powermate_device {
dma_addr_t configcr_dma; dma_addr_t configcr_dma;
struct usb_device *udev; struct usb_device *udev;
struct input_dev input; struct input_dev input;
struct semaphore lock; spinlock_t lock;
int static_brightness; int static_brightness;
int pulse_speed; int pulse_speed;
int pulse_table; int pulse_table;
...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) ...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs)
__FUNCTION__, retval); __FUNCTION__, retval);
} }
/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
static void powermate_sync_state(struct powermate_device *pm) static void powermate_sync_state(struct powermate_device *pm)
{ {
if (pm->requires_update == 0) if (pm->requires_update == 0)
...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm) ...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm)
static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
{ {
struct powermate_device *pm = urb->context; struct powermate_device *pm = urb->context;
unsigned long flags;
if (urb->status) if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
down(&pm->lock); spin_lock_irqsave(&pm->lock, flags);
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Set the LED up as described and begin the sync with the hardware if required */ /* Set the LED up as described and begin the sync with the hardware if required */
static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake) int pulse_table, int pulse_asleep, int pulse_awake)
{ {
unsigned long flags;
if (pulse_speed < 0) if (pulse_speed < 0)
pulse_speed = 0; pulse_speed = 0;
if (pulse_table < 0) if (pulse_table < 0)
...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
pulse_asleep = !!pulse_asleep; pulse_asleep = !!pulse_asleep;
pulse_awake = !!pulse_awake; pulse_awake = !!pulse_awake;
down(&pm->lock);
spin_lock_irqsave(&pm->lock, flags);
/* mark state updates which are required */ /* mark state updates which are required */
if (static_brightness != pm->static_brightness){ if (static_brightness != pm->static_brightness){
...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Callback from the Input layer when an event arrives from userspace to configure the LED */ /* Callback from the Input layer when an event arrives from userspace to configure the LED */
...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
return -ENOMEM; return -ENOMEM;
} }
init_MUTEX(&pm->lock); pm->lock = SPIN_LOCK_UNLOCKED;
init_input_dev(&pm->input); init_input_dev(&pm->input);
/* get a handle to the interrupt data pipe */ /* get a handle to the interrupt data pipe */
...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf) ...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (pm) { if (pm) {
down(&pm->lock);
pm->requires_update = 0; pm->requires_update = 0;
usb_unlink_urb(pm->irq); usb_unlink_urb(pm->irq);
input_unregister_device(&pm->input); input_unregister_device(&pm->input);
......
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