On Mon, 21 May 2007, Oliver Neukum wrote: > Am Mittwoch, 16. Mai 2007 17:20 schrieb Alan Stern: > > > @@ -592,8 +604,21 @@ static int hid_get_class_descriptor(stru > > > int usbhid_open(struct hid_device *hid) > > > { > > > struct usbhid_device *usbhid = hid->driver_data; > > > + int res; > > > > > > - hid->open++; > > > + mutex_lock(&hid_open_mut); > > > + if (!hid->open++) { > > > + res = usb_autopm_get_interface(usbhid->intf); > > > + /* the device must be awake to reliable request remote > > > wakeup */ > > > + if (res < 0) { > > > + hid->open--; > > > + mutex_unlock(&hid_open_mut); > > > + return -EIO; > > > + } > > > + usbhid->intf->needs_remote_wakeup = 1; > > > + usb_autopm_put_interface(usbhid->intf); > > > + } > > > + mutex_unlock(&hid_open_mut); > > > if (hid_start_in(hid)) > > > hid_io_error(hid); > > > return 0; > > > > Don't you need to do usb_autopm_get_interface() before hid_start_in()? > > hid_start_in() takes the spinlock and checks for a suspension. In the > unlikely case that the device already has been suspended, remote > wakeup must be active and resume() will call hid_start_in() again.
But this code runs whenever a process opens the device file. If the device is suspended at that time, there might not be a remote wakeup request pending. So you'd run into trouble unless you did an autoresume before calling hid_start_in(). > > > @@ -1154,13 +1184,26 @@ static int hid_suspend(struct usb_interf > > > struct usbhid_device *usbhid = hid->driver_data; > > > struct usb_device *udev = interface_to_usbdev(intf); > > > > > > - > > > - spin_lock_irq(&usbhid->inlock); > > > - set_bit(HID_REPORTED_IDLE, &usbhid->iofl); > > > - spin_unlock_irq(&usbhid->inlock); > > > - if (usbhid_wait_io(hid) < 0) > > > - return -EIO; > > > - > > > + if (udev->auto_pm) { > > > + spin_lock_irq(&usbhid->inlock); /* Sync with error handler > > > */ > > > + if (!test_bit(HID_RESET_PENDING, &usbhid->iofl) > > > + && !test_bit(HID_CLEAR_HALT, &usbhid->iofl) > > > + && !test_bit(HID_OUT_RUNNING, &usbhid->iofl) > > > + && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) > > > + { > > > + set_bit(HID_REPORTED_IDLE, &usbhid->iofl); > > > + spin_unlock_irq(&usbhid->inlock); > > > + } else { > > > + spin_unlock_irq(&usbhid->inlock); > > > + return -EBUSY; > > > + } > > > + } else { > > > + spin_lock_irq(&usbhid->inlock); > > > + set_bit(HID_REPORTED_IDLE, &usbhid->iofl); > > > + spin_unlock_irq(&usbhid->inlock); > > > + if (usbhid_wait_io(hid) < 0) > > > + return -EIO; > > > + } > > > del_timer(&usbhid->io_retry); > > > usb_kill_urb(usbhid->urbin); > > > flush_scheduled_work(); > > > > This might be simpler if you inverted the order of the tests. That is, > > first get the spinlock, then test for > > > > udev->auto_pm && (test_bit() || test_bit() || ...) > > But that would put code needlessly under lock. A single test of udev->auto_pm! I think it would be worthwhile for the improvements in comprehensibility and code size. > > to see if you need to fail right away. You probably don't even need to > > check udev->auto_pm again before calling usbhid_wait_io. > > > > > @@ -1175,6 +1218,7 @@ static int hid_resume(struct usb_interfa > > > int status; > > > > > > clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); > > > + usbhid_mark_busy(usbhid); > > > usbhid->retry_delay = 0; > > > status = hid_start_in(hid); > > > usbhid_restart_queues(usbhid); > > > > Again, don't you need to call usb_autopm_get_interface() before > > hid_start_in()? > > resume() and suspend() have mutual exclusion, don't they? So > the device must be awake while resume() is running. Oh, yes. My mistake. > > One last thing, about the race between a last-minute URB completion and > > autosuspend. The USB autosuspend core routine doesn't check the > > last_busy value after suspending the interface drivers and before > > suspending the device. Do we need to? > > As the lock is per device, the resume() call would wait and proceed > immediately after suspend() drops the lock. I see no problem. I guess it's just a theoretical problem. The whole point of the last_busy field is to prevent autosuspend too soon after any I/O. So if an URB does complete and nevertheless the device is suspended a few milliseconds later, then last_busy hasn't fulfilled its role. Like this: The autosuspend timer expires. last_busy is sufficiently old. hid_suspend() is called. The interrupt URB completes. last_busy is set to jiffies. hid_suspend() kills the interrupt URB and returns. usbcore doesn't notice that last_busy has been changed. usbcore suspends the device. It's not actually _wrong_, but it isn't optimal. Alan Stern ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel