ChangeSet 1.1743.3.10, 2004/05/25 11:00:18-07:00, jamesl@appliedminds.com [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: [] __might_sleep+0xb2/0xd3 May 18 06:56:01 Knoppix kernel: [] powermate_config_complete+0x33/0x77 [powermate] May 18 06:56:01 Knoppix kernel: [] usb_hcd_giveback_urb+0x25/0x39 May 18 06:56:01 Knoppix kernel: [] uhci_finish_urb+0x54/0xa1 May 18 06:56:01 Knoppix kernel: [] uhci_finish_completion+0x43/0x55 May 18 06:56:01 Knoppix kernel: [] uhci_irq+0xf8/0x179 May 18 06:56:01 Knoppix kernel: [] usb_hcd_irq+0x36/0x67 May 18 06:56:01 Knoppix kernel: [] handle_IRQ_event+0x3a/0x64 May 18 06:56:01 Knoppix kernel: [] do_IRQ+0xb8/0x192 May 18 06:56:01 Knoppix kernel: [] common_interrupt+0x18/0x20 Attached patch uses spinlocks instead of a semaphore so that we can't sleep when in_atomic(). drivers/usb/input/powermate.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-) diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Fri May 28 14:41:06 2004 +++ b/drivers/usb/input/powermate.c Fri May 28 14:41:06 2004 @@ -33,6 +33,7 @@ #include #include #include +#include #include #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ @@ -67,7 +68,7 @@ dma_addr_t configcr_dma; struct usb_device *udev; struct input_dev input; - struct semaphore lock; + spinlock_t lock; int static_brightness; int pulse_speed; int pulse_table; @@ -116,7 +117,7 @@ __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) { if (pm->requires_update == 0) @@ -194,19 +195,22 @@ static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) { struct powermate_device *pm = urb->context; + unsigned long flags; if (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); - up(&pm->lock); + spin_unlock_irqrestore(&pm->lock, flags); } /* 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, int pulse_table, int pulse_asleep, int pulse_awake) { + unsigned long flags; + if (pulse_speed < 0) pulse_speed = 0; if (pulse_table < 0) @@ -219,7 +223,8 @@ pulse_asleep = !!pulse_asleep; pulse_awake = !!pulse_awake; - down(&pm->lock); + + spin_lock_irqsave(&pm->lock, flags); /* mark state updates which are required */ if (static_brightness != pm->static_brightness){ @@ -242,7 +247,7 @@ 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 */ @@ -344,7 +349,7 @@ return -ENOMEM; } - init_MUTEX(&pm->lock); + pm->lock = SPIN_LOCK_UNLOCKED; init_input_dev(&pm->input); /* get a handle to the interrupt data pipe */ @@ -411,7 +416,6 @@ usb_set_intfdata(intf, NULL); if (pm) { - down(&pm->lock); pm->requires_update = 0; usb_unlink_urb(pm->irq); input_unregister_device(&pm->input);