<div dir="ltr"><div>So you're saying that every time we're suspended, we simply throw out the entire context and drop all the devices on the floor, as if you just unplugged all of them?<br><br></div><div>I suppose I just never thought of that. On first though, I don't see anything wrong with that.<br>
<br>If that's what we should do, should we remove libinput_suspend / libinput_resume then?<br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Mar 17, 2014 at 11:21 PM, Peter Hutterer <span dir="ltr"><<a href="mailto:peter.hutterer@who-t.net" target="_blank">peter.hutterer@who-t.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Sat, Mar 15, 2014 at 07:59:29PM +0100, Jonas Ådahl wrote:<br>
> On Thu, Mar 13, 2014 at 04:18:20PM +1000, Peter Hutterer wrote:<br>
> > When a libinput context for a given seat is initialized, not all devices may<br>
> > be available. Some or all devices may be paused by systemd-logind. Waiting for<br>
> > a unplug event is not appropriate here as the devices are physically<br>
> > available, just prevented from getting access.<br>
> ><br>
> > Add a libinput_udev_rescan_devices() function that triggers a scan of all<br>
> > devices on the current udev seat. Devices that do not exist on the seat are<br>
> > added, devices that already exist on the seat but have been revoked are<br>
> > removed.<br>
> ><br>
> > Note that devices that have been physically removed are not removed, instead<br>
> > we wait for the udev event to handle this for us.<br>
> ><br>
> > Signed-off-by: Peter Hutterer <<a href="mailto:peter.hutterer@who-t.net">peter.hutterer@who-t.net</a>><br>
> > ---<br>
> > The idea here is basically to start a udev context as usual. If the<br>
> > compositor doesn't have the session, open_restricted will fail. Once the<br>
> > ResumeDevice signals are handled by the compositor it can ask libinput to<br>
> > rescan the device list to add the ones that failed before (or remove revoked<br>
> > ones).<br>
> ><br>
> > Notes on why this approach:<br>
> > * libinput_device_suspend()/resume() seems nicer at first but if a device<br>
> >   fails to open, we don't have a libinput_device context. handling that<br>
> >   would make the API complicated since we cannot guarantee that all<br>
> >   libinput_device_* functions (specificall has_capability) work on all<br>
> >   devices anymore.<br>
> > * I suspect in the 90% case the the PauseDevice/ResumeDevice signals come in<br>
> >   in a batch anyway, so the compositor should be able to optimise this to<br>
> >   one single call<br>
> > * this is a udev specific call, for the path backend the compositor can and<br>
> >   should maintain the devices manually anyway<br>
> > * EVIOCGVERSION was picked because it always succeeds, except after revoke<br>
> ><br>
> > This is an RFC at this point, let me know if that approach works. Still need<br>
> > to write tests and better evdev duplicate detection - right now there is a<br>
> > race condition that could remove the wrong device.<br>
><br>
> Hi,<br>
><br>
> So what this patch is trying to solve is handling the following flow:<br>
><br>
> * create libinput udev context<br>
>  - some or all devices will fail to open due to being paused<br>
> * devices are resumed<br>
><br>
> What stops us from simply doing<br>
><br>
> * devices are resumed<br>
> * create libinput udev context<br>
<br>
</div></div>Jasper? you can answer that better than me<br>
<div class=""><br>
> As you say, a compositor should be able to know when it should rescan,<br>
> and in most cases (?) before this, we won't get a single device anyway<br>
> so whats the point of creating earlier than that? For resuming after<br>
> session switch I suppose we'd have the same problem, but this would then<br>
> just work the same:<br>
><br>
> * devices are resumed<br>
> * resume libinput context<br>
<br>
</div>the question here is: is there a use-case for a single device to be<br>
paused/resumed outside of the usual process? David?<br>
<br>
We're struggling with this in X but that's caused by a completely different<br>
problem and is rather orthogonal to this.<br>
<br>
Cheers,<br>
   Peter<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
> >  src/evdev.c     | 15 +++++++++++++++<br>
> >  src/evdev.h     |  2 ++<br>
> >  src/libinput.h  | 21 +++++++++++++++++++++<br>
> >  src/udev-seat.c | 46 +++++++++++++++++++++++++++++++++++++++++-----<br>
> >  4 files changed, 79 insertions(+), 5 deletions(-)<br>
> ><br>
> > diff --git a/src/evdev.c b/src/evdev.c<br>
> > index ba7c8b3..018fbb1 100644<br>
> > --- a/src/evdev.c<br>
> > +++ b/src/evdev.c<br>
> > @@ -790,3 +790,18 @@ evdev_device_destroy(struct evdev_device *device)<br>
> >     free(device->sysname);<br>
> >     free(device);<br>
> >  }<br>
> > +<br>
> > +int<br>
> > +evdev_device_is_alive(struct evdev_device *device)<br>
> > +{<br>
> > +   int rc;<br>
> > +   int version;<br>
> > +<br>
> > +   rc = ioctl(device->fd, EVIOCGVERSION, &version);<br>
> > +<br>
> > +   if (rc < 0 && errno != ENODEV)<br>
> > +           log_info("evdev: %s failed with errno %d (%s)\n",<br>
> > +                    __func__, errno, strerror(errno));<br>
> > +<br>
> > +   return rc != -1;<br>
> > +}<br>
> > diff --git a/src/evdev.h b/src/evdev.h<br>
> > index b83a2f9..82a3873 100644<br>
> > --- a/src/evdev.h<br>
> > +++ b/src/evdev.h<br>
> > @@ -156,4 +156,6 @@ evdev_device_remove(struct evdev_device *device);<br>
> >  void<br>
> >  evdev_device_destroy(struct evdev_device *device);<br>
> ><br>
> > +int<br>
> > +evdev_device_is_alive(struct evdev_device *device);<br>
> >  #endif /* EVDEV_H */<br>
> > diff --git a/src/libinput.h b/src/libinput.h<br>
> > index 3e09871..dadcac2 100644<br>
> > --- a/src/libinput.h<br>
> > +++ b/src/libinput.h<br>
> > @@ -715,6 +715,27 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface,<br>
> >  /**<br>
> >   * @ingroup base<br>
> >   *<br>
> > + * Re-scan the list of devices available to this context. Devices in the<br>
> > + * seat specified in libinput_udev_create_for_seat() that previously have<br>
> > + * failed to initialize are re-initialized. Devices that have successfully<br>
> > + * re-initialized but are now revoked are removed.<br>
> > + *<br>
> > + * Calling libinput_udev_rescan_devices() on a context suspended with<br>
> > + * libinput_suspend() does nothing.<br>
> > + *<br>
> > + * @note This function should not be used for detection of physically added<br>
> > + * or removed devices, libinput_dispatch() detects those. This function<br>
> > + * should only be used to re-open or close existing devices, e.g. if<br>
> > + * systemd-logind prevented access to a device before.<br>
> > + *<br>
> > + * @param libinput The previously initialized libinput context<br>
> > + */<br>
> > +void<br>
> > +libinput_udev_rescan_devices(struct libinput *libinput);<br>
> > +<br>
> > +/**<br>
> > + * @ingroup base<br>
> > + *<br>
> >   * Create a new libinput context that requires the caller to manually add or<br>
> >   * remove devices with libinput_path_add_device() and<br>
> >   * libinput_path_remove_device().<br>
> > diff --git a/src/udev-seat.c b/src/udev-seat.c<br>
> > index 366c92b..5b09e4b 100644<br>
> > --- a/src/udev-seat.c<br>
> > +++ b/src/udev-seat.c<br>
> > @@ -136,12 +136,28 @@ device_removed(struct udev_device *udev_device, struct udev_input *input)<br>
> >     }<br>
> >  }<br>
> ><br>
> > +static struct evdev_device*<br>
> > +udev_input_find_device_by_sysname(struct udev_input *input, const char *sysname)<br>
> > +{<br>
> > +   struct udev_seat *seat;<br>
> > +   struct evdev_device *device;<br>
> > +<br>
> > +   list_for_each(seat, &input->base.seat_list, base.link) {<br>
> > +           list_for_each(device, &seat->base.devices_list, base.link)<br>
> > +                   if (!strcmp(device->sysname, sysname)) {<br>
> > +                           return device;<br>
> > +                   }<br>
> > +   }<br>
> > +   return NULL;<br>
> > +}<br>
> > +<br>
> >  static int<br>
> >  udev_input_add_devices(struct udev_input *input, struct udev *udev)<br>
> >  {<br>
> >     struct udev_enumerate *e;<br>
> >     struct udev_list_entry *entry;<br>
> >     struct udev_device *device;<br>
> > +   struct evdev_device *evdev;<br>
> >     const char *path, *sysname;<br>
> ><br>
> >     e = udev_enumerate_new(udev);<br>
> > @@ -157,11 +173,15 @@ udev_input_add_devices(struct udev_input *input, struct udev *udev)<br>
> >                     continue;<br>
> >             }<br>
> ><br>
> > -           if (device_added(device, input) < 0) {<br>
> > -                   udev_device_unref(device);<br>
> > -                   udev_enumerate_unref(e);<br>
> > -                   return -1;<br>
> > -           }<br>
> > +           evdev = udev_input_find_device_by_sysname(input, sysname);<br>
> > +           if (!evdev) {<br>
> > +                   if (device_added(device, input) < 0) {<br>
> > +                           udev_device_unref(device);<br>
> > +                           udev_enumerate_unref(e);<br>
> > +                           return -1;<br>
> > +                   }<br>
> > +           } else if (!evdev_device_is_alive(evdev))<br>
> > +                   device_removed(device, input);<br>
> ><br>
> >             udev_device_unref(device);<br>
> >     }<br>
> > @@ -364,3 +384,19 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface,<br>
> ><br>
> >     return &input->base;<br>
> >  }<br>
> > +<br>
> > +LIBINPUT_EXPORT void<br>
> > +libinput_udev_rescan_devices(struct libinput *libinput)<br>
> > +{<br>
> > +   struct udev_input *udev_input = (struct udev_input*)libinput;<br>
> > +<br>
> > +   if (libinput->interface_backend != &interface_backend) {<br>
> > +           log_error("Mismatching backends. This is an application bug.\n");<br>
> > +           return;<br>
> > +   }<br>
> > +<br>
> > +   if (udev_input->udev_monitor == NULL)<br>
> > +           return;<br>
> > +<br>
> > +   udev_input_add_devices(udev_input, udev_input->udev);<br>
> > +}<br>
> > --<br>
> > 1.8.5.3<br>
> ><br>
> > _______________________________________________<br>
> > wayland-devel mailing list<br>
> > <a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
> > <a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>  Jasper<br>
</div>