diff mbox

[RFC,05/12] HID: wiimote: Synchronize wiimote input and hid event handling

Message ID 1308095157-4699-6-git-send-email-dh.herrmann@googlemail.com (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

David Herrmann June 14, 2011, 11:45 p.m. UTC
The wiimote first starts HID hardware and then registers the input
device. We need to synchronize the startup so no event handler will
start parsing events when the wiimote device is not ready, yet.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/hid-wiimote.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

Comments

Oliver Neukum June 15, 2011, 6:34 a.m. UTC | #1
Am Mittwoch, 15. Juni 2011, 01:45:50 schrieb David Herrmann:
> The wiimote first starts HID hardware and then registers the input
> device. We need to synchronize the startup so no event handler will
> start parsing events when the wiimote device is not ready, yet.

Hi,

here the fun begins. Using atomic ops is not for the faint of heart.
The problem is that atomic_t guarantees atomicity, not ordering.
Tasks on on other CPUs reading wdata->ready==1 does not mean
that they'll read anything else written before that as it was written
or the old value. You need smp barriers.

> 
> Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
> ---
>  drivers/hid/hid-wiimote.c |   13 +++++++++++++
>  1 files changed, 13 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
> index 9fa4fe1..4dbb2c1 100644
> --- a/drivers/hid/hid-wiimote.c
> +++ b/drivers/hid/hid-wiimote.c
> @@ -10,6 +10,7 @@
>   * any later version.
>   */
>  
> +#include <linux/atomic.h>
>  #include <linux/device.h>
>  #include <linux/hid.h>
>  #include <linux/input.h>
> @@ -20,6 +21,7 @@
>  #define WIIMOTE_NAME "Nintendo Wii Remote"
>  
>  struct wiimote_data {
> +	atomic_t ready;
>  	struct hid_device *hdev;
>  	struct input_dev *input;
>  };
> @@ -27,12 +29,22 @@ struct wiimote_data {
>  static int wiimote_input_event(struct input_dev *dev, unsigned int type,
>  						unsigned int code, int value)
>  {
> +	struct wiimote_data *wdata = input_get_drvdata(dev);
> +
> +	if (!atomic_read(&wdata->ready))
> +		return -EBUSY;
> +

Here an smp_rmb()

>  	return 0;
>  }
>  
>  static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
>  							u8 *raw_data, int size)
>  {
> +	struct wiimote_data *wdata = hid_get_drvdata(hdev);
> +
> +	if (!atomic_read(&wdata->ready))
> +		return -EBUSY;
> +
>  	if (size < 1)
>  		return -EINVAL;
>  
> @@ -98,6 +110,7 @@ static int wiimote_hid_probe(struct hid_device *hdev,
>  		goto err_stop;
>  	}
>

Here an smp_wmb()
It is redundant because input_register_device takes a spinlock which
implies a barrier, but you'll make the automated checking tools happier.  
> +	atomic_set(&wdata->ready, 1);
>  	hid_info(hdev, "New device registered\n");
>  	return 0;

	Regards
		Oliver
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Kosina June 16, 2011, 9:20 a.m. UTC | #2
On Wed, 15 Jun 2011, Oliver Neukum wrote:

> > Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
> > ---
> >  drivers/hid/hid-wiimote.c |   13 +++++++++++++
> >  1 files changed, 13 insertions(+), 0 deletions(-)
> > 
> > diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
> > index 9fa4fe1..4dbb2c1 100644
> > --- a/drivers/hid/hid-wiimote.c
> > +++ b/drivers/hid/hid-wiimote.c
> > @@ -10,6 +10,7 @@
> >   * any later version.
> >   */
> >  
> > +#include <linux/atomic.h>
> >  #include <linux/device.h>
> >  #include <linux/hid.h>
> >  #include <linux/input.h>
> > @@ -20,6 +21,7 @@
> >  #define WIIMOTE_NAME "Nintendo Wii Remote"
> >  
> >  struct wiimote_data {
> > +	atomic_t ready;
> >  	struct hid_device *hdev;
> >  	struct input_dev *input;
> >  };
> > @@ -27,12 +29,22 @@ struct wiimote_data {
> >  static int wiimote_input_event(struct input_dev *dev, unsigned int type,
> >  						unsigned int code, int value)
> >  {
> > +	struct wiimote_data *wdata = input_get_drvdata(dev);
> > +
> > +	if (!atomic_read(&wdata->ready))
> > +		return -EBUSY;
> > +
> 
> Here an smp_rmb()
> 
> >  	return 0;
> >  }
> >  
> >  static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
> >  							u8 *raw_data, int size)
> >  {
> > +	struct wiimote_data *wdata = hid_get_drvdata(hdev);
> > +
> > +	if (!atomic_read(&wdata->ready))
> > +		return -EBUSY;
> > +
> >  	if (size < 1)
> >  		return -EINVAL;
> >  
> > @@ -98,6 +110,7 @@ static int wiimote_hid_probe(struct hid_device *hdev,
> >  		goto err_stop;
> >  	}
> >
> 
> Here an smp_wmb()
> It is redundant because input_register_device takes a spinlock which
> implies a barrier, but you'll make the automated checking tools happier.  

Yeah, spinlock implies SMP barrier implicitly.

I don't think adding barriers just to make some buggy automatic checker 
happy is worth it.

Thanks for the review, Oliver.
Oliver Neukum June 16, 2011, 10:18 a.m. UTC | #3
Am Donnerstag, 16. Juni 2011, 11:20:18 schrieb Jiri Kosina:
> > Here an smp_wmb()
> > It is redundant because input_register_device takes a spinlock which
> > implies a barrier, but you'll make the automated checking tools happier.  
> 
> Yeah, spinlock implies SMP barrier implicitly.
> 
> I don't think adding barriers just to make some buggy automatic checker 
> happy is worth it.

Fine by me as long as the problem is understood.

	Regards
		Oliver
David Herrmann June 16, 2011, 10:29 a.m. UTC | #4
On Thu, Jun 16, 2011 at 12:18 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Donnerstag, 16. Juni 2011, 11:20:18 schrieb Jiri Kosina:
>> > Here an smp_wmb()
>> > It is redundant because input_register_device takes a spinlock which
>> > implies a barrier, but you'll make the automated checking tools happier.
>>
>> Yeah, spinlock implies SMP barrier implicitly.
>>
>> I don't think adding barriers just to make some buggy automatic checker
>> happy is worth it.
>
> Fine by me as long as the problem is understood.

Does that mean that I can omit the smp_rmb(), too? I do not like
relying on input_register_device to use a spinlock. It makes reading
the code hard, so I added both barriers. Should I remove them again or
keep them?

Thank you for reviewing. I have fixed all your concerns. I will resend
the patches if there are no more comments on the code as [PATCH] in
few days.

Regards
David
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oliver Neukum June 16, 2011, 10:42 a.m. UTC | #5
Am Donnerstag, 16. Juni 2011, 12:29:40 schrieb David Herrmann:
> On Thu, Jun 16, 2011 at 12:18 PM, Oliver Neukum <oneukum@suse.de> wrote:
> > Am Donnerstag, 16. Juni 2011, 11:20:18 schrieb Jiri Kosina:
> >> > Here an smp_wmb()
> >> > It is redundant because input_register_device takes a spinlock which
> >> > implies a barrier, but you'll make the automated checking tools happier.
> >>
> >> Yeah, spinlock implies SMP barrier implicitly.
> >>
> >> I don't think adding barriers just to make some buggy automatic checker
> >> happy is worth it.
> >
> > Fine by me as long as the problem is understood.
> 
> Does that mean that I can omit the smp_rmb(), too? I do not like
> relying on input_register_device to use a spinlock. It makes reading
> the code hard, so I added both barriers. Should I remove them again or
> keep them?

The full explanation is in Documentation/atomic-ops.txt
Basically, whenever you do

if (!descriptor->flag)
	return -ERR;

descriptor->pointer->member = expression; //or anything else with the pointer

you need smp_rmb() in between

If you do

if (!descriptor->flag)
	return -ERR;

// no use of pointer here

spin_lock(&lock);

descriptor->pointer->member = expression; //or anything else with the pointer

You are save and can do without the smp_rmb()

But, you still need smp_rmb() if you do:

if (!descriptor->flag)
	return -ERR;

// no use of pointer here

spin_lock(&descriptor->pointer->lock);

All clear? I must say I stopped listing and checking all the places you use
the flag, but I think some were buggy.

	Regards
		Oliver
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 9fa4fe1..4dbb2c1 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -10,6 +10,7 @@ 
  * any later version.
  */
 
+#include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/input.h>
@@ -20,6 +21,7 @@ 
 #define WIIMOTE_NAME "Nintendo Wii Remote"
 
 struct wiimote_data {
+	atomic_t ready;
 	struct hid_device *hdev;
 	struct input_dev *input;
 };
@@ -27,12 +29,22 @@  struct wiimote_data {
 static int wiimote_input_event(struct input_dev *dev, unsigned int type,
 						unsigned int code, int value)
 {
+	struct wiimote_data *wdata = input_get_drvdata(dev);
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
 	return 0;
 }
 
 static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
 							u8 *raw_data, int size)
 {
+	struct wiimote_data *wdata = hid_get_drvdata(hdev);
+
+	if (!atomic_read(&wdata->ready))
+		return -EBUSY;
+
 	if (size < 1)
 		return -EINVAL;
 
@@ -98,6 +110,7 @@  static int wiimote_hid_probe(struct hid_device *hdev,
 		goto err_stop;
 	}
 
+	atomic_set(&wdata->ready, 1);
 	hid_info(hdev, "New device registered\n");
 	return 0;