Re: [PATCH 2/5] m5mols: Replace IRQ workqueue to waitqueue only

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/21/2011 09:35 AM, HeungJun, Kim wrote:
> In M-5MOLS driver, the workqueue code for IRQ is hard to re-use. So, remove
> the IRQ workqueue, and use only waitqueue for waiting IRQ with timeout.
> The info->issue has the status that interrupt is issued or not, then
> the info->interrupt has the IRQ status register at that time.
> 
> Signed-off-by: HeungJun, Kim<riverful.kim@xxxxxxxxxxx>
> Signed-off-by: Kyungmin Park<kyungmin.park@xxxxxxxxxxx>
> ---
>   drivers/media/video/m5mols/m5mols.h         |    7 +--
>   drivers/media/video/m5mols/m5mols_capture.c |   34 ++-------------
>   drivers/media/video/m5mols/m5mols_core.c    |   60 +++++++++++----------------
>   3 files changed, 32 insertions(+), 69 deletions(-)
> 
> diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
> index c8e1572..75f7984 100644
> --- a/drivers/media/video/m5mols/m5mols.h
> +++ b/drivers/media/video/m5mols/m5mols.h
> @@ -164,7 +164,6 @@ struct m5mols_version {
>    * @res_type: current resolution type
>    * @code: current code
>    * @irq_waitq: waitqueue for the capture
> - * @work_irq: workqueue for the IRQ
>    * @flags: state variable for the interrupt handler
>    * @handle: control handler
>    * @autoexposure: Auto Exposure control
> @@ -181,6 +180,7 @@ struct m5mols_version {
>    * @lock_ae: true means the Auto Exposure is locked
>    * @lock_awb: true means the Aut WhiteBalance is locked
>    * @resolution:	register value for current resolution
> + * @issue: "true" means the M-5MOLS sensor's interrupt issued
>    * @interrupt: register value for current interrupt status
>    * @mode: register value for current operation mode
>    * @mode_save: register value for current operation mode for saving
> @@ -194,7 +194,6 @@ struct m5mols_info {
>   	int res_type;
>   	enum v4l2_mbus_pixelcode code;
>   	wait_queue_head_t irq_waitq;
> -	struct work_struct work_irq;
>   	unsigned long flags;
> 
>   	struct v4l2_ctrl_handler handle;
> @@ -211,6 +210,7 @@ struct m5mols_info {
>   	struct m5mols_version ver;
>   	struct m5mols_capture cap;
>   	bool power;
> +	bool issue;
>   	bool ctrl_sync;
>   	bool lock_ae;
>   	bool lock_awb;
> @@ -221,8 +221,6 @@ struct m5mols_info {
>   	int (*set_power)(struct device *dev, int on);
>   };
> 
> -#define ST_CAPT_IRQ 0
> -
>   #define is_powered(__info) (__info->power)
>   #define is_ctrl_synced(__info) (__info->ctrl_sync)
>   #define is_available_af(__info)	(__info->ver.af)
> @@ -283,6 +281,7 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
>   int m5mols_mode(struct m5mols_info *info, u8 mode);
> 
>   int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
> +int m5mols_timeout_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
>   int m5mols_sync_controls(struct m5mols_info *info);
>   int m5mols_start_capture(struct m5mols_info *info);
>   int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
> diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
> index 3248ac8..18a56bf 100644
> --- a/drivers/media/video/m5mols/m5mols_capture.c
> +++ b/drivers/media/video/m5mols/m5mols_capture.c
> @@ -29,22 +29,6 @@
>   #include "m5mols.h"
>   #include "m5mols_reg.h"
> 
> -static int m5mols_capture_error_handler(struct m5mols_info *info,
> -					int timeout)
> -{
> -	int ret;
> -
> -	/* Disable all interrupts and clear relevant interrupt staus bits */
> -	ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
> -			   info->interrupt&  ~(REG_INT_CAPTURE));
> -	if (ret)
> -		return ret;
> -
> -	if (timeout == 0)
> -		return -ETIMEDOUT;
> -
> -	return 0;
> -}
>   /**
>    * m5mols_read_rational - I2C read of a rational number
>    *
> @@ -121,7 +105,6 @@ int m5mols_start_capture(struct m5mols_info *info)
>   {
>   	struct v4l2_subdev *sd =&info->sd;
>   	u8 resolution = info->resolution;
> -	int timeout;
>   	int ret;
> 
>   	/*
> @@ -142,14 +125,9 @@ int m5mols_start_capture(struct m5mols_info *info)
>   		ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
>   	if (!ret)
>   		ret = m5mols_mode(info, REG_CAPTURE);
> -	if (!ret) {
> +	if (!ret)
>   		/* Wait for capture interrupt, after changing capture mode */
> -		timeout = wait_event_interruptible_timeout(info->irq_waitq,
> -					   test_bit(ST_CAPT_IRQ,&info->flags),
> -					   msecs_to_jiffies(2000));
> -		if (test_and_clear_bit(ST_CAPT_IRQ,&info->flags))
> -			ret = m5mols_capture_error_handler(info, timeout);
> -	}
> +		ret = m5mols_timeout_interrupt(sd, REG_INT_CAPTURE, 2000);
>   	if (!ret)
>   		ret = m5mols_lock_3a(info, false);
>   	if (ret)
> @@ -175,15 +153,13 @@ int m5mols_start_capture(struct m5mols_info *info)
>   		ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
>   	if (!ret) {
>   		/* Wait for the capture completion interrupt */
> -		timeout = wait_event_interruptible_timeout(info->irq_waitq,
> -					   test_bit(ST_CAPT_IRQ,&info->flags),
> -					   msecs_to_jiffies(2000));
> -		if (test_and_clear_bit(ST_CAPT_IRQ,&info->flags)) {
> +		ret = m5mols_timeout_interrupt(sd, REG_INT_CAPTURE, 2000);
> +		if (!ret) {
>   			ret = m5mols_capture_info(info);
>   			if (!ret)
>   				v4l2_subdev_notify(sd, 0,&info->cap.total);
>   		}
>   	}
> 
> -	return m5mols_capture_error_handler(info, timeout);
> +	return ret;
>   }
> diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
> index 73db96e..f3b9415 100644
> --- a/drivers/media/video/m5mols/m5mols_core.c
> +++ b/drivers/media/video/m5mols/m5mols_core.c
> @@ -333,6 +333,28 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
>   	return ret;
>   }
> 
> +/* m5mols_timeout_interrupt - Wait interrupt and figure out which interrupt. */
> +int m5mols_timeout_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout)

Could this be m5mols_wait_interrupt() instead ?

> +{
> +	struct m5mols_info *info = to_m5mols(sd);
> +	u8 reg;
> +	int timed;
> +	int ret;
> +
> +	timed = wait_event_interruptible_timeout(info->irq_waitq,
> +			info->issue, msecs_to_jiffies(timeout));

I'm a bit sceptic about replacing current atomic test with a non atomic one.
Using bit operations (test_and_clear_bit() ?) could probably save us from loosing 
any interrupt. Still, there might be no problem if you're careful enough.

> +	if (!timed)
> +		return -ETIMEDOUT;
> +
> +	ret = m5mols_busy_val(sd, condition,&reg, CAT_SYSTEM, CAT0_INT_FACTOR);
> +	if (ret || (!ret&&  reg != condition))

It could be simplified to:

	if (ret || reg != condition)

> +		return -EINVAL;
> +
> +	info->interrupt = reg;
> +	info->issue = false;

I think this might be racy, as this variable is also being changed in the interrupt
handler. 

> +	return 0;
> +}
> +
>   /**
>    * m5mols_reg_mode - Write the mode and check busy status
>    *
> @@ -901,46 +923,13 @@ static const struct v4l2_subdev_ops m5mols_ops = {
>   	.video		=&m5mols_video_ops,
>   };
> 
> -static void m5mols_irq_work(struct work_struct *work)
> -{
> -	struct m5mols_info *info =
> -		container_of(work, struct m5mols_info, work_irq);
> -	struct v4l2_subdev *sd =&info->sd;
> -	u8 reg;
> -	int ret;
> -
> -	if (!is_powered(info) ||
> -			m5mols_read_u8(sd, SYSTEM_INT_FACTOR,&info->interrupt))
> -		return;
> -
> -	switch (info->interrupt&  REG_INT_MASK) {
> -	case REG_INT_AF:
> -		if (!is_available_af(info))
> -			break;
> -		ret = m5mols_read_u8(sd, AF_STATUS,&reg);
> -		v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
> -			 reg == REG_AF_FAIL ? "Failed" :
> -			 reg == REG_AF_SUCCESS ? "Success" :
> -			 reg == REG_AF_IDLE ? "Idle" : "Busy");
> -		break;
> -	case REG_INT_CAPTURE:
> -		if (!test_and_set_bit(ST_CAPT_IRQ,&info->flags))
> -			wake_up_interruptible(&info->irq_waitq);
> -
> -		v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
> -		break;
> -	default:
> -		v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
> -		break;
> -	};
> -}
> -
>   static irqreturn_t m5mols_irq_handler(int irq, void *data)
>   {
>   	struct v4l2_subdev *sd = data;
>   	struct m5mols_info *info = to_m5mols(sd);
> 
> -	schedule_work(&info->work_irq);
> +	info->issue = true;
> +	wake_up_interruptible(&info->irq_waitq);
> 
>   	return IRQ_HANDLED;
>   }
> @@ -999,7 +988,6 @@ static int __devinit m5mols_probe(struct i2c_client *client,
>   	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
> 
>   	init_waitqueue_head(&info->irq_waitq);
> -	INIT_WORK(&info->work_irq, m5mols_irq_work);
>   	ret = request_irq(client->irq, m5mols_irq_handler,
>   			  IRQF_TRIGGER_RISING, MODULE_NAME, sd);
>   	if (ret) {

--
Regards,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux