diff mbox

DVB/V4L: ov511 - export snapshot button through input layer

Message ID 20090904054805.5C944526EA5@mailhub.coreip.homeip.net (mailing list archive)
State Rejected
Headers show

Commit Message

Dmitry Torokhov Sept. 4, 2009, 5:15 a.m. UTC
From: Bastien Nocera <hadess@hadess.net>

Register an input device with one button, and for the supported
OV511 webcams, poll and check whether the snapshot button has been
pressed on each new frame.

[dtor@mail.ru: fix freeing of phys, plug into Kconfig, make compile]
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

Mauro,

This is something that's been sitting in my queue for quite some
time, please consider applying.

Thanks!

 drivers/media/video/Kconfig |    8 +++
 drivers/media/video/ov511.c |  109 +++++++++++++++++++++++++++++++++++++++----
 drivers/media/video/ov511.h |    8 +++
 3 files changed, 116 insertions(+), 9 deletions(-)

Comments

Laurent Pinchart Sept. 4, 2009, 8:37 a.m. UTC | #1
On Friday 04 September 2009 07:15:07 Dmitry Torokhov wrote:
> From: Bastien Nocera <hadess@hadess.net>
>
> Register an input device with one button, and for the supported
> OV511 webcams, poll and check whether the snapshot button has been
> pressed on each new frame.
>
> [dtor@mail.ru: fix freeing of phys, plug into Kconfig, make compile]
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
> ---
>
> Mauro,
>
> This is something that's been sitting in my queue for quite some
> time, please consider applying.
>
> Thanks!
>
>  drivers/media/video/Kconfig |    8 +++
>  drivers/media/video/ov511.c |  109
> +++++++++++++++++++++++++++++++++++++++---- drivers/media/video/ov511.h |  
>  8 +++
>  3 files changed, 116 insertions(+), 9 deletions(-)
>
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index dcf9fa9..42573e0 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -888,6 +888,14 @@ config USB_OV511
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ov511.
>
> +config USB_OV511_SNAPSHOT_BUTTON
> +	bool "USB OV511 Snapshot Button support"
> +	depends on USB_OV511
> +	depends on INPUT
> +	---help---
> +	  Say Y here if you want the driver to report snapshot button through
> +	  input layer.
> +
>  config USB_SE401
>  	tristate "USB SE401 Camera support"
>  	depends on VIDEO_V4L1
> diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
> index 0bc2cf5..484165c 100644
> --- a/drivers/media/video/ov511.c
> +++ b/drivers/media/video/ov511.c
> @@ -44,6 +44,8 @@
>  #include <asm/processor.h>
>  #include <linux/mm.h>
>  #include <linux/device.h>
> +#include <linux/input.h>
> +#include <linux/usb/input.h>
>
>  #if defined (__i386__)
>  	#include <asm/cpufeature.h>
> @@ -92,7 +94,7 @@ static int cams			= 1;
>  static int compress;
>  static int testpat;
>  static int dumppix;
> -static int led 			= 1;
> +static int led			= 1;

There's a lot of white space cleanup in the patch that's unrelated to the 
subject. Could you put that in a separate patch ?

>  static int dump_bridge;
>  static int dump_sensor;
>  static int printph;
> @@ -352,6 +354,83 @@ rvfree(void *mem, unsigned long size)
>
>  /**********************************************************************
>   *
> + * Input device
> + *
> + **********************************************************************/
> +#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
> +
> +static int ov511_input_init(struct usb_ov511 *ov)
> +{
> +	struct usb_device *udev = ov->dev;
> +	struct input_dev *input;
> +	int err = -ENOMEM;
> +
> +	input = input_allocate_device();
> +	if (!input)
> +		goto err_out;
> +
> +	usb_make_path(udev, ov->key_phys, OV511_KEY_PHYS_SIZE);
> +	strlcat(ov->key_phys, "/input0", OV511_KEY_PHYS_SIZE);

What about sizeof(ov->key_phys) instead of OV511_KEY_PHYS_SIZE ?

> +
> +	input->name = "OV511 Snapshot Button";
> +	input->phys = ov->key_phys;
> +	usb_to_input_id(udev, &input->id);
> +	input->dev.parent = &udev->dev;
> +
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(KEY_CAMERA, input->keybit);
> +
> +	err = input_register_device(input);
> +	if (err)
> +		goto err_out;
> +
> +	ov->key_input = input;
> +	return 0;
> +
> +err_out:
> +	input_free_device(input);
> +	return err;
> +}
> +
> +static void ov511_input_cleanup(struct usb_ov511 *ov)
> +{
> +	if (ov->key_input) {
> +		input_unregister_device(ov->key_input);
> +		ov->key_input = NULL;
> +	}
> +}
> +
> +static void ov511_input_report_key(struct usb_ov511 *ov)
> +{
> +	struct input_dev *input = ov->key_input;
> +
> +	if (input) {
> +		input_report_key(input, KEY_CAMERA, 1);
> +		input_sync(input);
> +		input_report_key(input, KEY_CAMERA, 0);
> +		input_sync(input);
> +	}
> +}
> +
> +#else
> +
> +static inline int ov511_input_init(struct usb_ov511 *ov)
> +{
> +	return 0;
> +}
> +
> +static inline void ov511_input_cleanup(struct usb_ov511 *ov)
> +{
> +}
> +
> +static inline void ov511_input_report_key(struct usb_ov511 *ov)
> +{
> +}
> +
> +#endif /* CONFIG_USB_OV511_SNAPSHOT_BUTTON */
> +
> +/**********************************************************************
> + *
>   * Register I/O
>   *
>   **********************************************************************/
> @@ -1105,7 +1184,6 @@ ov51x_clear_snapshot(struct usb_ov511 *ov)
>  	}
>  }
>
> -#if 0
>  /* Checks the status of the snapshot button. Returns 1 if it was pressed
> since * it was last cleared, and zero in all other cases (including errors)
> */ static int
> @@ -1130,7 +1208,6 @@ ov51x_check_snapshot(struct usb_ov511 *ov)
>
>  	return status;
>  }
> -#endif
>
>  /* This does an initial reset of an OmniVision sensor and ensures that I2C
>   * is synchronized. Returns <0 for failure.
> @@ -3149,10 +3226,10 @@ ov51x_postprocess_yuv420(struct usb_ov511 *ov,
> struct ov511_frame *frame) }
>
>  /* Post-processes the specified frame. This consists of:
> - * 	1. Decompress frame, if necessary
> + *	1. Decompress frame, if necessary
>   *	2. Deinterlace frame and scale to proper size, if necessary
> - * 	3. Convert from YUV planar to destination format, if necessary
> - * 	4. Fix the RGB offset, if necessary
> + *	3. Convert from YUV planar to destination format, if necessary
> + *	4. Fix the RGB offset, if necessary
>   */
>  static void
>  ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
> @@ -4387,6 +4464,11 @@ redo:
>  			if ((ov->snap_enabled) && (frame->snapshot)) {
>  				frame->snapshot = 0;
>  				ov51x_clear_snapshot(ov);
> +			} else if (!ov->snap_enabled && ov->bclass == BCL_OV511) {
> +				if (ov51x_check_snapshot(ov) == 1) {
> +					ov511_input_report_key(ov);
> +					ov51x_clear_snapshot(ov);
> +				}
>  			}
>
>  			/* Decompression, format conversion, etc... */
> @@ -5237,7 +5319,7 @@ ov511_configure(struct usb_ov511 *ov)
>  	};
>
>  	static struct ov511_regvals aRegvalsNorm511[] = {
> -		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
> +		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0x01 },
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
> @@ -5400,7 +5482,7 @@ ov518_configure(struct usb_ov511 *ov)
>  	static struct ov511_regvals aRegvalsNorm518[] = {
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
> -		{ OV511_REG_BUS, 0x31, 			0x0f },
> +		{ OV511_REG_BUS, 0x31,			0x0f },
>  		{ OV511_REG_BUS, 0x5d,			0x03 },
>  		{ OV511_REG_BUS, 0x24,			0x9f },
>  		{ OV511_REG_BUS, 0x25,			0x90 },
> @@ -5413,7 +5495,7 @@ ov518_configure(struct usb_ov511 *ov)
>  	static struct ov511_regvals aRegvalsNorm518Plus[] = {
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
>  		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
> -		{ OV511_REG_BUS, 0x31, 			0x0f },
> +		{ OV511_REG_BUS, 0x31,			0x0f },
>  		{ OV511_REG_BUS, 0x5d,			0x03 },
>  		{ OV511_REG_BUS, 0x24,			0x9f },
>  		{ OV511_REG_BUS, 0x25,			0x90 },
> @@ -5880,6 +5962,13 @@ ov51x_probe(struct usb_interface *intf, const struct
> usb_device_id *id)
>
>  	mutex_lock(&ov->lock);
>
> +	/* Snapshot is currently only supported on OV511,
> +	 * so no need to register the input device if it's not supported */
> +	if (!ov->snap_enabled && ov->bclass == BCL_OV511) {
> +		if (ov511_input_init(ov) < 0)
> +			dev_warn(&ov->dev->dev, "Could not register input device\n");
> +	}
> +
>  	return 0;
>
>  error:
> @@ -5928,6 +6017,8 @@ ov51x_disconnect(struct usb_interface *intf)
>  	if (ov->vdev)
>  		video_unregister_device(ov->vdev);
>
> +	ov511_input_cleanup(ov);
> +
>  	for (n = 0; n < OV511_NUMFRAMES; n++)
>  		ov->frame[n].grabstate = FRAME_ERROR;
>
> diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
> index c450c92..7c0ade1 100644
> --- a/drivers/media/video/ov511.h
> +++ b/drivers/media/video/ov511.h
> @@ -259,6 +259,9 @@
>  /* Size of usb_make_path() buffer */
>  #define OV511_USB_PATH_LEN	64
>
> +/* Size of 'phys' field for the snapshot button input device */
> +#define OV511_KEY_PHYS_SIZE	64
> +
>  /* Bridge types */
>  enum {
>  	BRG_UNKNOWN,
> @@ -469,6 +472,11 @@ struct usb_ov511 {
>
>  	int snap_enabled;	/* Snapshot mode enabled */
>
> +#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
> +	struct input_dev *key_input;
> +	char key_phys[OV511_KEY_PHYS_SIZE];
> +#endif
> +
>  	int bridge;		/* Type of bridge (BRG_*) */
>  	int bclass;		/* Class of bridge (BCL_*) */
>  	int sensor;		/* Type of image sensor chip (SEN_*) */
Dmitry Torokhov Sept. 4, 2009, 9:02 a.m. UTC | #2
On Friday 04 September 2009 01:37:46 am Laurent Pinchart wrote:
> > +     usb_make_path(udev, ov->key_phys, OV511_KEY_PHYS_SIZE);
> > +     strlcat(ov->key_phys, "/input0", OV511_KEY_PHYS_SIZE);
> 
> What about sizeof(ov->key_phys) instead of OV511_KEY_PHYS_SIZE ?

I don't really have preference.
Hans de Goede Sept. 6, 2009, 9:13 a.m. UTC | #3
Hi,

The ov511 driver is a v4l1 driver and is deprecated, all supported webcams
are now supported by the gspca_ov519 driver.

Can you please do a patch to the gspca_ov519 driver instead?

Note that the gspca_sn9c20x driver already has support for input events,
if possible please try to locate common code and move that to gspca.c

Regards,

Hans


On 09/04/2009 07:15 AM, Dmitry Torokhov wrote:
> From: Bastien Nocera<hadess@hadess.net>
>
> Register an input device with one button, and for the supported
> OV511 webcams, poll and check whether the snapshot button has been
> pressed on each new frame.
>
> [dtor@mail.ru: fix freeing of phys, plug into Kconfig, make compile]
> Signed-off-by: Bastien Nocera<hadess@hadess.net>
> Signed-off-by: Dmitry Torokhov<dtor@mail.ru>
> ---
>
> Mauro,
>
> This is something that's been sitting in my queue for quite some
> time, please consider applying.
>
> Thanks!
>
>   drivers/media/video/Kconfig |    8 +++
>   drivers/media/video/ov511.c |  109 +++++++++++++++++++++++++++++++++++++++----
>   drivers/media/video/ov511.h |    8 +++
>   3 files changed, 116 insertions(+), 9 deletions(-)
>
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index dcf9fa9..42573e0 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -888,6 +888,14 @@ config USB_OV511
>   	  To compile this driver as a module, choose M here: the
>   	  module will be called ov511.
>
> +config USB_OV511_SNAPSHOT_BUTTON
> +	bool "USB OV511 Snapshot Button support"
> +	depends on USB_OV511
> +	depends on INPUT
> +	---help---
> +	  Say Y here if you want the driver to report snapshot button through
> +	  input layer.
> +
>   config USB_SE401
>   	tristate "USB SE401 Camera support"
>   	depends on VIDEO_V4L1
> diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
> index 0bc2cf5..484165c 100644
> --- a/drivers/media/video/ov511.c
> +++ b/drivers/media/video/ov511.c
> @@ -44,6 +44,8 @@
>   #include<asm/processor.h>
>   #include<linux/mm.h>
>   #include<linux/device.h>
> +#include<linux/input.h>
> +#include<linux/usb/input.h>
>
>   #if defined (__i386__)
>   	#include<asm/cpufeature.h>
> @@ -92,7 +94,7 @@ static int cams			= 1;
>   static int compress;
>   static int testpat;
>   static int dumppix;
> -static int led 			= 1;
> +static int led			= 1;
>   static int dump_bridge;
>   static int dump_sensor;
>   static int printph;
> @@ -352,6 +354,83 @@ rvfree(void *mem, unsigned long size)
>
>   /**********************************************************************
>    *
> + * Input device
> + *
> + **********************************************************************/
> +#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
> +
> +static int ov511_input_init(struct usb_ov511 *ov)
> +{
> +	struct usb_device *udev = ov->dev;
> +	struct input_dev *input;
> +	int err = -ENOMEM;
> +
> +	input = input_allocate_device();
> +	if (!input)
> +		goto err_out;
> +
> +	usb_make_path(udev, ov->key_phys, OV511_KEY_PHYS_SIZE);
> +	strlcat(ov->key_phys, "/input0", OV511_KEY_PHYS_SIZE);
> +
> +	input->name = "OV511 Snapshot Button";
> +	input->phys = ov->key_phys;
> +	usb_to_input_id(udev,&input->id);
> +	input->dev.parent =&udev->dev;
> +
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(KEY_CAMERA, input->keybit);
> +
> +	err = input_register_device(input);
> +	if (err)
> +		goto err_out;
> +
> +	ov->key_input = input;
> +	return 0;
> +
> +err_out:
> +	input_free_device(input);
> +	return err;
> +}
> +
> +static void ov511_input_cleanup(struct usb_ov511 *ov)
> +{
> +	if (ov->key_input) {
> +		input_unregister_device(ov->key_input);
> +		ov->key_input = NULL;
> +	}
> +}
> +
> +static void ov511_input_report_key(struct usb_ov511 *ov)
> +{
> +	struct input_dev *input = ov->key_input;
> +
> +	if (input) {
> +		input_report_key(input, KEY_CAMERA, 1);
> +		input_sync(input);
> +		input_report_key(input, KEY_CAMERA, 0);
> +		input_sync(input);
> +	}
> +}
> +
> +#else
> +
> +static inline int ov511_input_init(struct usb_ov511 *ov)
> +{
> +	return 0;
> +}
> +
> +static inline void ov511_input_cleanup(struct usb_ov511 *ov)
> +{
> +}
> +
> +static inline void ov511_input_report_key(struct usb_ov511 *ov)
> +{
> +}
> +
> +#endif /* CONFIG_USB_OV511_SNAPSHOT_BUTTON */
> +
> +/**********************************************************************
> + *
>    * Register I/O
>    *
>    **********************************************************************/
> @@ -1105,7 +1184,6 @@ ov51x_clear_snapshot(struct usb_ov511 *ov)
>   	}
>   }
>
> -#if 0
>   /* Checks the status of the snapshot button. Returns 1 if it was pressed since
>    * it was last cleared, and zero in all other cases (including errors) */
>   static int
> @@ -1130,7 +1208,6 @@ ov51x_check_snapshot(struct usb_ov511 *ov)
>
>   	return status;
>   }
> -#endif
>
>   /* This does an initial reset of an OmniVision sensor and ensures that I2C
>    * is synchronized. Returns<0 for failure.
> @@ -3149,10 +3226,10 @@ ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
>   }
>
>   /* Post-processes the specified frame. This consists of:
> - * 	1. Decompress frame, if necessary
> + *	1. Decompress frame, if necessary
>    *	2. Deinterlace frame and scale to proper size, if necessary
> - * 	3. Convert from YUV planar to destination format, if necessary
> - * 	4. Fix the RGB offset, if necessary
> + *	3. Convert from YUV planar to destination format, if necessary
> + *	4. Fix the RGB offset, if necessary
>    */
>   static void
>   ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
> @@ -4387,6 +4464,11 @@ redo:
>   			if ((ov->snap_enabled)&&  (frame->snapshot)) {
>   				frame->snapshot = 0;
>   				ov51x_clear_snapshot(ov);
> +			} else if (!ov->snap_enabled&&  ov->bclass == BCL_OV511) {
> +				if (ov51x_check_snapshot(ov) == 1) {
> +					ov511_input_report_key(ov);
> +					ov51x_clear_snapshot(ov);
> +				}
>   			}
>
>   			/* Decompression, format conversion, etc... */
> @@ -5237,7 +5319,7 @@ ov511_configure(struct usb_ov511 *ov)
>   	};
>
>   	static struct ov511_regvals aRegvalsNorm511[] = {
> -		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
> +		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0x01 },
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
> @@ -5400,7 +5482,7 @@ ov518_configure(struct usb_ov511 *ov)
>   	static struct ov511_regvals aRegvalsNorm518[] = {
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
> -		{ OV511_REG_BUS, 0x31, 			0x0f },
> +		{ OV511_REG_BUS, 0x31,			0x0f },
>   		{ OV511_REG_BUS, 0x5d,			0x03 },
>   		{ OV511_REG_BUS, 0x24,			0x9f },
>   		{ OV511_REG_BUS, 0x25,			0x90 },
> @@ -5413,7 +5495,7 @@ ov518_configure(struct usb_ov511 *ov)
>   	static struct ov511_regvals aRegvalsNorm518Plus[] = {
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
>   		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
> -		{ OV511_REG_BUS, 0x31, 			0x0f },
> +		{ OV511_REG_BUS, 0x31,			0x0f },
>   		{ OV511_REG_BUS, 0x5d,			0x03 },
>   		{ OV511_REG_BUS, 0x24,			0x9f },
>   		{ OV511_REG_BUS, 0x25,			0x90 },
> @@ -5880,6 +5962,13 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
>
>   	mutex_lock(&ov->lock);
>
> +	/* Snapshot is currently only supported on OV511,
> +	 * so no need to register the input device if it's not supported */
> +	if (!ov->snap_enabled&&  ov->bclass == BCL_OV511) {
> +		if (ov511_input_init(ov)<  0)
> +			dev_warn(&ov->dev->dev, "Could not register input device\n");
> +	}
> +
>   	return 0;
>
>   error:
> @@ -5928,6 +6017,8 @@ ov51x_disconnect(struct usb_interface *intf)
>   	if (ov->vdev)
>   		video_unregister_device(ov->vdev);
>
> +	ov511_input_cleanup(ov);
> +
>   	for (n = 0; n<  OV511_NUMFRAMES; n++)
>   		ov->frame[n].grabstate = FRAME_ERROR;
>
> diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
> index c450c92..7c0ade1 100644
> --- a/drivers/media/video/ov511.h
> +++ b/drivers/media/video/ov511.h
> @@ -259,6 +259,9 @@
>   /* Size of usb_make_path() buffer */
>   #define OV511_USB_PATH_LEN	64
>
> +/* Size of 'phys' field for the snapshot button input device */
> +#define OV511_KEY_PHYS_SIZE	64
> +
>   /* Bridge types */
>   enum {
>   	BRG_UNKNOWN,
> @@ -469,6 +472,11 @@ struct usb_ov511 {
>
>   	int snap_enabled;	/* Snapshot mode enabled */
>
> +#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
> +	struct input_dev *key_input;
> +	char key_phys[OV511_KEY_PHYS_SIZE];
> +#endif
> +
>   	int bridge;		/* Type of bridge (BRG_*) */
>   	int bclass;		/* Class of bridge (BCL_*) */
>   	int sensor;		/* Type of image sensor chip (SEN_*) */
--
To unsubscribe from this list: send the line "unsubscribe linux-media" 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/media/video/Kconfig b/drivers/media/video/Kconfig
index dcf9fa9..42573e0 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -888,6 +888,14 @@  config USB_OV511
 	  To compile this driver as a module, choose M here: the
 	  module will be called ov511.
 
+config USB_OV511_SNAPSHOT_BUTTON
+	bool "USB OV511 Snapshot Button support"
+	depends on USB_OV511
+	depends on INPUT
+	---help---
+	  Say Y here if you want the driver to report snapshot button through
+	  input layer.
+
 config USB_SE401
 	tristate "USB SE401 Camera support"
 	depends on VIDEO_V4L1
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 0bc2cf5..484165c 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -44,6 +44,8 @@ 
 #include <asm/processor.h>
 #include <linux/mm.h>
 #include <linux/device.h>
+#include <linux/input.h>
+#include <linux/usb/input.h>
 
 #if defined (__i386__)
 	#include <asm/cpufeature.h>
@@ -92,7 +94,7 @@  static int cams			= 1;
 static int compress;
 static int testpat;
 static int dumppix;
-static int led 			= 1;
+static int led			= 1;
 static int dump_bridge;
 static int dump_sensor;
 static int printph;
@@ -352,6 +354,83 @@  rvfree(void *mem, unsigned long size)
 
 /**********************************************************************
  *
+ * Input device
+ *
+ **********************************************************************/
+#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
+
+static int ov511_input_init(struct usb_ov511 *ov)
+{
+	struct usb_device *udev = ov->dev;
+	struct input_dev *input;
+	int err = -ENOMEM;
+
+	input = input_allocate_device();
+	if (!input)
+		goto err_out;
+
+	usb_make_path(udev, ov->key_phys, OV511_KEY_PHYS_SIZE);
+	strlcat(ov->key_phys, "/input0", OV511_KEY_PHYS_SIZE);
+
+	input->name = "OV511 Snapshot Button";
+	input->phys = ov->key_phys;
+	usb_to_input_id(udev, &input->id);
+	input->dev.parent = &udev->dev;
+
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(KEY_CAMERA, input->keybit);
+
+	err = input_register_device(input);
+	if (err)
+		goto err_out;
+
+	ov->key_input = input;
+	return 0;
+
+err_out:
+	input_free_device(input);
+	return err;
+}
+
+static void ov511_input_cleanup(struct usb_ov511 *ov)
+{
+	if (ov->key_input) {
+		input_unregister_device(ov->key_input);
+		ov->key_input = NULL;
+	}
+}
+
+static void ov511_input_report_key(struct usb_ov511 *ov)
+{
+	struct input_dev *input = ov->key_input;
+
+	if (input) {
+		input_report_key(input, KEY_CAMERA, 1);
+		input_sync(input);
+		input_report_key(input, KEY_CAMERA, 0);
+		input_sync(input);
+	}
+}
+
+#else
+
+static inline int ov511_input_init(struct usb_ov511 *ov)
+{
+	return 0;
+}
+
+static inline void ov511_input_cleanup(struct usb_ov511 *ov)
+{
+}
+
+static inline void ov511_input_report_key(struct usb_ov511 *ov)
+{
+}
+
+#endif /* CONFIG_USB_OV511_SNAPSHOT_BUTTON */
+
+/**********************************************************************
+ *
  * Register I/O
  *
  **********************************************************************/
@@ -1105,7 +1184,6 @@  ov51x_clear_snapshot(struct usb_ov511 *ov)
 	}
 }
 
-#if 0
 /* Checks the status of the snapshot button. Returns 1 if it was pressed since
  * it was last cleared, and zero in all other cases (including errors) */
 static int
@@ -1130,7 +1208,6 @@  ov51x_check_snapshot(struct usb_ov511 *ov)
 
 	return status;
 }
-#endif
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
  * is synchronized. Returns <0 for failure.
@@ -3149,10 +3226,10 @@  ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
 }
 
 /* Post-processes the specified frame. This consists of:
- * 	1. Decompress frame, if necessary
+ *	1. Decompress frame, if necessary
  *	2. Deinterlace frame and scale to proper size, if necessary
- * 	3. Convert from YUV planar to destination format, if necessary
- * 	4. Fix the RGB offset, if necessary
+ *	3. Convert from YUV planar to destination format, if necessary
+ *	4. Fix the RGB offset, if necessary
  */
 static void
 ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
@@ -4387,6 +4464,11 @@  redo:
 			if ((ov->snap_enabled) && (frame->snapshot)) {
 				frame->snapshot = 0;
 				ov51x_clear_snapshot(ov);
+			} else if (!ov->snap_enabled && ov->bclass == BCL_OV511) {
+				if (ov51x_check_snapshot(ov) == 1) {
+					ov511_input_report_key(ov);
+					ov51x_clear_snapshot(ov);
+				}
 			}
 
 			/* Decompression, format conversion, etc... */
@@ -5237,7 +5319,7 @@  ov511_configure(struct usb_ov511 *ov)
 	};
 
 	static struct ov511_regvals aRegvalsNorm511[] = {
-		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
+		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0x01 },
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
@@ -5400,7 +5482,7 @@  ov518_configure(struct usb_ov511 *ov)
 	static struct ov511_regvals aRegvalsNorm518[] = {
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
-		{ OV511_REG_BUS, 0x31, 			0x0f },
+		{ OV511_REG_BUS, 0x31,			0x0f },
 		{ OV511_REG_BUS, 0x5d,			0x03 },
 		{ OV511_REG_BUS, 0x24,			0x9f },
 		{ OV511_REG_BUS, 0x25,			0x90 },
@@ -5413,7 +5495,7 @@  ov518_configure(struct usb_ov511 *ov)
 	static struct ov511_regvals aRegvalsNorm518Plus[] = {
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 }, /* Reset */
 		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 }, /* Enable */
-		{ OV511_REG_BUS, 0x31, 			0x0f },
+		{ OV511_REG_BUS, 0x31,			0x0f },
 		{ OV511_REG_BUS, 0x5d,			0x03 },
 		{ OV511_REG_BUS, 0x24,			0x9f },
 		{ OV511_REG_BUS, 0x25,			0x90 },
@@ -5880,6 +5962,13 @@  ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 	mutex_lock(&ov->lock);
 
+	/* Snapshot is currently only supported on OV511,
+	 * so no need to register the input device if it's not supported */
+	if (!ov->snap_enabled && ov->bclass == BCL_OV511) {
+		if (ov511_input_init(ov) < 0)
+			dev_warn(&ov->dev->dev, "Could not register input device\n");
+	}
+
 	return 0;
 
 error:
@@ -5928,6 +6017,8 @@  ov51x_disconnect(struct usb_interface *intf)
 	if (ov->vdev)
 		video_unregister_device(ov->vdev);
 
+	ov511_input_cleanup(ov);
+
 	for (n = 0; n < OV511_NUMFRAMES; n++)
 		ov->frame[n].grabstate = FRAME_ERROR;
 
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index c450c92..7c0ade1 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -259,6 +259,9 @@ 
 /* Size of usb_make_path() buffer */
 #define OV511_USB_PATH_LEN	64
 
+/* Size of 'phys' field for the snapshot button input device */
+#define OV511_KEY_PHYS_SIZE	64
+
 /* Bridge types */
 enum {
 	BRG_UNKNOWN,
@@ -469,6 +472,11 @@  struct usb_ov511 {
 
 	int snap_enabled;	/* Snapshot mode enabled */
 
+#ifdef CONFIG_USB_OV511_SNAPSHOT_BUTTON
+	struct input_dev *key_input;
+	char key_phys[OV511_KEY_PHYS_SIZE];
+#endif
+
 	int bridge;		/* Type of bridge (BRG_*) */
 	int bclass;		/* Class of bridge (BCL_*) */
 	int sensor;		/* Type of image sensor chip (SEN_*) */