All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [media] rc-core: move timeout and checks to lirc
@ 2012-08-16 22:15 Sean Young
  2012-08-16 23:12 ` Mauro Carvalho Chehab
  2012-08-24 22:16 ` David Härdeman
  0 siblings, 2 replies; 11+ messages in thread
From: Sean Young @ 2012-08-16 22:15 UTC (permalink / raw)
  To: David Härdeman; +Cc: Jarod Wilson, linux-media

 
> The lirc TX functionality expects the process which writes (TX) data to
> the lirc dev to sleep until the actual data has been transmitted by the
> hardware.
> 
> Since the same timeout calculation is duplicated in more than one driver
> (and would have to be duplicated in even more drivers as they gain TX
> support), it makes sense to move this timeout calculation to the lirc
> layer instead.
> 
> At the same time, centralize some of the sanity checks.
> 
> Signed-off-by: David Härdeman <david@hardeman.nu>
> Cc: Jarod Wilson <jwilson@redhat.com>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> ---
>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>  drivers/media/rc/mceusb.c        | 18 ------------------
>  drivers/media/rc/rc-loopback.c   | 12 ------------
>  3 files changed, 29 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
> index d2fd064..6ad4a07 100644
> --- a/drivers/media/rc/ir-lirc-codec.c
> +++ b/drivers/media/rc/ir-lirc-codec.c
> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>  	unsigned int *txbuf; /* buffer with values to transmit */
>  	ssize_t ret = -EINVAL;
>  	size_t count;
> +	ktime_t start;
> +	s64 towait;
> +	unsigned int duration = 0; /* signal duration in us */
> +	int i;
> +
> +	start = ktime_get();
>  
>  	lirc = lirc_get_pdata(file);
>  	if (!lirc)
> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>  		goto out;
>  	}
>  
> -	if (dev->tx_ir)
> -		ret = dev->tx_ir(dev, txbuf, count);
> +	if (!dev->tx_ir) {
> +		ret = -ENOSYS;
> +		goto out;
> +	}
> +
> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
> +	if (ret < 0)
> +		goto out;
> +
> +	for (i = 0; i < ret; i++)
> +		duration += txbuf[i];
>  
> -	if (ret > 0)
> -		ret *= sizeof(unsigned);
> +	ret *= sizeof(unsigned int);
> +
> +	/*
> +	 * The lircd gap calculation expects the write function to
> +	 * wait for the actual IR signal to be transmitted before
> +	 * returning.
> +	 */
> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
> +	if (towait > 0) {
> +		set_current_state(TASK_INTERRUPTIBLE);
> +		schedule_timeout(usecs_to_jiffies(towait));
> +	}
>  
>  out:

You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
sense for some devices. However you haven't updated winbond-cir.c which
does two things:

1) Modifies the txbuf (which is now used after transmit)
2) Does the sleeping already since it blocks on the device to complete.

Surely if the driver can block on the device to complete then that is 
better than sleeping; there might some difference due to rounding and 
clock skew.

In addition to winbond-cir, iguanair suffer from the same problem. There
might be others.

Could we have a flag in rc_dev to signify whether a driver blocks on
completion of a transmit and only sleep here if it is not set?

e.g. rc_dev.tx_blocks_until_complete

The wording could be improved.

Another alternative would be if the drivers provided a 
"wait_for_tx_to_complete()" function. If they can provided that; using 
that it would be possible to implement O_NONBLOCK and sync.

>  	kfree(txbuf);
> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
> index d289fd4..a5c6c1c 100644
> --- a/drivers/media/rc/mceusb.c
> +++ b/drivers/media/rc/mceusb.c
> @@ -791,10 +791,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>  	int i, ret = 0;
>  	int cmdcount = 0;
>  	unsigned char *cmdbuf; /* MCE command buffer */
> -	long signal_duration = 0; /* Singnal length in us */
> -	struct timeval start_time, end_time;
> -
> -	do_gettimeofday(&start_time);
>  
>  	cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
>  	if (!cmdbuf)
> @@ -807,7 +803,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>  
>  	/* Generate mce packet data */
>  	for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
> -		signal_duration += txbuf[i];
>  		txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
>  
>  		do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
> @@ -850,19 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>  	/* Transmit the command to the mce device */
>  	mce_async_out(ir, cmdbuf, cmdcount);
>  
> -	/*
> -	 * The lircd gap calculation expects the write function to
> -	 * wait the time it takes for the ircommand to be sent before
> -	 * it returns.
> -	 */
> -	do_gettimeofday(&end_time);
> -	signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
> -			   (end_time.tv_sec - start_time.tv_sec) * 1000000;
> -
> -	/* delay with the closest number of ticks */
> -	set_current_state(TASK_INTERRUPTIBLE);
> -	schedule_timeout(usecs_to_jiffies(signal_duration));
> -
>  out:
>  	kfree(cmdbuf);
>  	return ret ? ret : count;
> diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
> index fae1615..f9be681 100644
> --- a/drivers/media/rc/rc-loopback.c
> +++ b/drivers/media/rc/rc-loopback.c
> @@ -105,18 +105,9 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>  {
>  	struct loopback_dev *lodev = dev->priv;
>  	u32 rxmask;
> -	unsigned total_duration = 0;
>  	unsigned i;
>  	DEFINE_IR_RAW_EVENT(rawir);
>  
> -	for (i = 0; i < count; i++)
> -		total_duration += abs(txbuf[i]);
> -
> -	if (total_duration == 0) {
> -		dprintk("invalid tx data, total duration zero\n");
> -		return -EINVAL;
> -	}
> -
>  	if (lodev->txcarrier < lodev->rxcarriermin ||
>  	    lodev->txcarrier > lodev->rxcarriermax) {
>  		dprintk("ignoring tx, carrier out of range\n");
> @@ -148,9 +139,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>  	ir_raw_event_handle(dev);
>  
>  out:
> -	/* Lirc expects this function to take as long as the total duration */
> -	set_current_state(TASK_INTERRUPTIBLE);
> -	schedule_timeout(usecs_to_jiffies(total_duration));
>  	return count;
>  }
>  
> -- 
> 1.7.11.2
> 

Sean

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-16 22:15 [media] rc-core: move timeout and checks to lirc Sean Young
@ 2012-08-16 23:12 ` Mauro Carvalho Chehab
  2012-08-20 21:36   ` David Härdeman
  2012-08-24 22:16 ` David Härdeman
  1 sibling, 1 reply; 11+ messages in thread
From: Mauro Carvalho Chehab @ 2012-08-16 23:12 UTC (permalink / raw)
  To: Sean Young; +Cc: David Härdeman, Jarod Wilson, linux-media

Em 16-08-2012 19:15, Sean Young escreveu:
>  
>> The lirc TX functionality expects the process which writes (TX) data to
>> the lirc dev to sleep until the actual data has been transmitted by the
>> hardware.
>>
>> Since the same timeout calculation is duplicated in more than one driver
>> (and would have to be duplicated in even more drivers as they gain TX
>> support), it makes sense to move this timeout calculation to the lirc
>> layer instead.
>>
>> At the same time, centralize some of the sanity checks.
>>
>> Signed-off-by: David Härdeman <david@hardeman.nu>
>> Cc: Jarod Wilson <jwilson@redhat.com>
>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>> ---
>>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>>  drivers/media/rc/mceusb.c        | 18 ------------------
>>  drivers/media/rc/rc-loopback.c   | 12 ------------
>>  3 files changed, 29 insertions(+), 34 deletions(-)
>>
>> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
>> index d2fd064..6ad4a07 100644
>> --- a/drivers/media/rc/ir-lirc-codec.c
>> +++ b/drivers/media/rc/ir-lirc-codec.c
>> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>  	unsigned int *txbuf; /* buffer with values to transmit */
>>  	ssize_t ret = -EINVAL;
>>  	size_t count;
>> +	ktime_t start;
>> +	s64 towait;
>> +	unsigned int duration = 0; /* signal duration in us */
>> +	int i;
>> +
>> +	start = ktime_get();
>>  
>>  	lirc = lirc_get_pdata(file);
>>  	if (!lirc)
>> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>  		goto out;
>>  	}
>>  
>> -	if (dev->tx_ir)
>> -		ret = dev->tx_ir(dev, txbuf, count);
>> +	if (!dev->tx_ir) {
>> +		ret = -ENOSYS;
>> +		goto out;
>> +	}
>> +
>> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
>> +	if (ret < 0)
>> +		goto out;
>> +
>> +	for (i = 0; i < ret; i++)
>> +		duration += txbuf[i];
>>  
>> -	if (ret > 0)
>> -		ret *= sizeof(unsigned);
>> +	ret *= sizeof(unsigned int);
>> +
>> +	/*
>> +	 * The lircd gap calculation expects the write function to
>> +	 * wait for the actual IR signal to be transmitted before
>> +	 * returning.
>> +	 */
>> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
>> +	if (towait > 0) {
>> +		set_current_state(TASK_INTERRUPTIBLE);
>> +		schedule_timeout(usecs_to_jiffies(towait));
>> +	}
>>  
>>  out:
> 
> You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
> sense for some devices. However you haven't updated winbond-cir.c which
> does two things:
> 
> 1) Modifies the txbuf (which is now used after transmit)
> 2) Does the sleeping already since it blocks on the device to complete.
> 
> Surely if the driver can block on the device to complete then that is 
> better than sleeping; there might some difference due to rounding and 
> clock skew.
> 
> In addition to winbond-cir, iguanair suffer from the same problem. There
> might be others.

That's likely my fault: I was waiting for Jarod's review on this patch,
with didn't happen, likely because he is too busy with some other stuff.
Both winbond and iguanair drivers went after David's patch.

Feel free to send me a patch fixing it there.

> Could we have a flag in rc_dev to signify whether a driver blocks on
> completion of a transmit and only sleep here if it is not set?
> 
> e.g. rc_dev.tx_blocks_until_complete
> 
> The wording could be improved.
> 
> Another alternative would be if the drivers provided a 
> "wait_for_tx_to_complete()" function. If they can provided that; using 
> that it would be possible to implement O_NONBLOCK and sync.

Seems fine on my eyes. It may avoid code duplication if you pass the fd 
flags to the lirc call, and add a code there that will wait for complete, 
if the device was not opened in block mode.

Regards,
mauro

> 
>>  	kfree(txbuf);
>> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
>> index d289fd4..a5c6c1c 100644
>> --- a/drivers/media/rc/mceusb.c
>> +++ b/drivers/media/rc/mceusb.c
>> @@ -791,10 +791,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>>  	int i, ret = 0;
>>  	int cmdcount = 0;
>>  	unsigned char *cmdbuf; /* MCE command buffer */
>> -	long signal_duration = 0; /* Singnal length in us */
>> -	struct timeval start_time, end_time;
>> -
>> -	do_gettimeofday(&start_time);
>>  
>>  	cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
>>  	if (!cmdbuf)
>> @@ -807,7 +803,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>>  
>>  	/* Generate mce packet data */
>>  	for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
>> -		signal_duration += txbuf[i];
>>  		txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
>>  
>>  		do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
>> @@ -850,19 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>>  	/* Transmit the command to the mce device */
>>  	mce_async_out(ir, cmdbuf, cmdcount);
>>  
>> -	/*
>> -	 * The lircd gap calculation expects the write function to
>> -	 * wait the time it takes for the ircommand to be sent before
>> -	 * it returns.
>> -	 */
>> -	do_gettimeofday(&end_time);
>> -	signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
>> -			   (end_time.tv_sec - start_time.tv_sec) * 1000000;
>> -
>> -	/* delay with the closest number of ticks */
>> -	set_current_state(TASK_INTERRUPTIBLE);
>> -	schedule_timeout(usecs_to_jiffies(signal_duration));
>> -
>>  out:
>>  	kfree(cmdbuf);
>>  	return ret ? ret : count;
>> diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
>> index fae1615..f9be681 100644
>> --- a/drivers/media/rc/rc-loopback.c
>> +++ b/drivers/media/rc/rc-loopback.c
>> @@ -105,18 +105,9 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>>  {
>>  	struct loopback_dev *lodev = dev->priv;
>>  	u32 rxmask;
>> -	unsigned total_duration = 0;
>>  	unsigned i;
>>  	DEFINE_IR_RAW_EVENT(rawir);
>>  
>> -	for (i = 0; i < count; i++)
>> -		total_duration += abs(txbuf[i]);
>> -
>> -	if (total_duration == 0) {
>> -		dprintk("invalid tx data, total duration zero\n");
>> -		return -EINVAL;
>> -	}
>> -
>>  	if (lodev->txcarrier < lodev->rxcarriermin ||
>>  	    lodev->txcarrier > lodev->rxcarriermax) {
>>  		dprintk("ignoring tx, carrier out of range\n");
>> @@ -148,9 +139,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
>>  	ir_raw_event_handle(dev);
>>  
>>  out:
>> -	/* Lirc expects this function to take as long as the total duration */
>> -	set_current_state(TASK_INTERRUPTIBLE);
>> -	schedule_timeout(usecs_to_jiffies(total_duration));
>>  	return count;
>>  }
>>  
>> -- 
>> 1.7.11.2
>>
> 
> Sean
> --
> 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
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-16 23:12 ` Mauro Carvalho Chehab
@ 2012-08-20 21:36   ` David Härdeman
  2012-08-20 22:02     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 11+ messages in thread
From: David Härdeman @ 2012-08-20 21:36 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Sean Young, Jarod Wilson, linux-media

On Thu, Aug 16, 2012 at 08:12:34PM -0300, Mauro Carvalho Chehab wrote:
>Em 16-08-2012 19:15, Sean Young escreveu:
>>  
>>> The lirc TX functionality expects the process which writes (TX) data to
>>> the lirc dev to sleep until the actual data has been transmitted by the
>>> hardware.
>>>
>>> Since the same timeout calculation is duplicated in more than one driver
>>> (and would have to be duplicated in even more drivers as they gain TX
>>> support), it makes sense to move this timeout calculation to the lirc
>>> layer instead.
>>>
>>> At the same time, centralize some of the sanity checks.
>>>
>>> Signed-off-by: David Härdeman <david@hardeman.nu>
>>> Cc: Jarod Wilson <jwilson@redhat.com>
>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>>> ---
>>>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>>>  drivers/media/rc/mceusb.c        | 18 ------------------
>>>  drivers/media/rc/rc-loopback.c   | 12 ------------
>>>  3 files changed, 29 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
>>> index d2fd064..6ad4a07 100644
>>> --- a/drivers/media/rc/ir-lirc-codec.c
>>> +++ b/drivers/media/rc/ir-lirc-codec.c
>>> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>  	unsigned int *txbuf; /* buffer with values to transmit */
>>>  	ssize_t ret = -EINVAL;
>>>  	size_t count;
>>> +	ktime_t start;
>>> +	s64 towait;
>>> +	unsigned int duration = 0; /* signal duration in us */
>>> +	int i;
>>> +
>>> +	start = ktime_get();
>>>  
>>>  	lirc = lirc_get_pdata(file);
>>>  	if (!lirc)
>>> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>  		goto out;
>>>  	}
>>>  
>>> -	if (dev->tx_ir)
>>> -		ret = dev->tx_ir(dev, txbuf, count);
>>> +	if (!dev->tx_ir) {
>>> +		ret = -ENOSYS;
>>> +		goto out;
>>> +	}
>>> +
>>> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
>>> +	if (ret < 0)
>>> +		goto out;
>>> +
>>> +	for (i = 0; i < ret; i++)
>>> +		duration += txbuf[i];
>>>  
>>> -	if (ret > 0)
>>> -		ret *= sizeof(unsigned);
>>> +	ret *= sizeof(unsigned int);
>>> +
>>> +	/*
>>> +	 * The lircd gap calculation expects the write function to
>>> +	 * wait for the actual IR signal to be transmitted before
>>> +	 * returning.
>>> +	 */
>>> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
>>> +	if (towait > 0) {
>>> +		set_current_state(TASK_INTERRUPTIBLE);
>>> +		schedule_timeout(usecs_to_jiffies(towait));
>>> +	}
>>>  
>>>  out:
>> 
>> You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
>> sense for some devices. However you haven't updated winbond-cir.c which
>> does two things:
>> 
>> 1) Modifies the txbuf (which is now used after transmit)
>> 2) Does the sleeping already since it blocks on the device to complete.
>> 
>> Surely if the driver can block on the device to complete then that is 
>> better than sleeping; there might some difference due to rounding and 
>> clock skew.
>> 
>> In addition to winbond-cir, iguanair suffer from the same problem. There
>> might be others.
>
>That's likely my fault: I was waiting for Jarod's review on this patch,
>with didn't happen, likely because he is too busy with some other stuff.
>Both winbond and iguanair drivers went after David's patch.
>
>Feel free to send me a patch fixing it there.
>
>> Could we have a flag in rc_dev to signify whether a driver blocks on
>> completion of a transmit and only sleep here if it is not set?
>> 
>> e.g. rc_dev.tx_blocks_until_complete
>> 
>> The wording could be improved.
>> 
>> Another alternative would be if the drivers provided a 
>> "wait_for_tx_to_complete()" function. If they can provided that; using 
>> that it would be possible to implement O_NONBLOCK and sync.
>
>Seems fine on my eyes. It may avoid code duplication if you pass the fd 
>flags to the lirc call, and add a code there that will wait for complete, 
>if the device was not opened in block mode.

I think a future rc-core native TX API should behave like a write() on a
network socket does.

That is, a write on a rc device opened with O_NONBLOCK will either
succeed immediately (i.e. write data to buffers for further processing)
or return EAGAIN.  A write on a non-O_NONBLOCK device will either write
the data to buffer space and return or wait for more space to be
available. No waiting for the data to actually leave the "device" (NIC
or IR transmitter) is done by the write() call.

The "gap calculation" that lirc wants to do based on the time a write()
takes to complete is quite non-unixy in my eyes and seems bogus.

If a user-space program wants a very specific and deterministic
behaviour, eg. wrt gaps...it should just add it to the TX data.

I.e. if you want to TX command "A", wait 150ms, TX command "B", then
instead of doing:

write(A); sleep(150ms); write(B);

the app should do:

write(A + 150ms silence + B);

The same goes for e.g. trailing silences after commands, etc...

-- 
David Härdeman

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-20 21:36   ` David Härdeman
@ 2012-08-20 22:02     ` Mauro Carvalho Chehab
  2012-08-20 22:10       ` Devin Heitmueller
                         ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Mauro Carvalho Chehab @ 2012-08-20 22:02 UTC (permalink / raw)
  To: David Härdeman; +Cc: Sean Young, Jarod Wilson, linux-media

Em 20-08-2012 18:36, David Härdeman escreveu:
> On Thu, Aug 16, 2012 at 08:12:34PM -0300, Mauro Carvalho Chehab wrote:
>> Em 16-08-2012 19:15, Sean Young escreveu:
>>>  
>>>> The lirc TX functionality expects the process which writes (TX) data to
>>>> the lirc dev to sleep until the actual data has been transmitted by the
>>>> hardware.
>>>>
>>>> Since the same timeout calculation is duplicated in more than one driver
>>>> (and would have to be duplicated in even more drivers as they gain TX
>>>> support), it makes sense to move this timeout calculation to the lirc
>>>> layer instead.
>>>>
>>>> At the same time, centralize some of the sanity checks.
>>>>
>>>> Signed-off-by: David Härdeman <david@hardeman.nu>
>>>> Cc: Jarod Wilson <jwilson@redhat.com>
>>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>>>> ---
>>>>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>>>>  drivers/media/rc/mceusb.c        | 18 ------------------
>>>>  drivers/media/rc/rc-loopback.c   | 12 ------------
>>>>  3 files changed, 29 insertions(+), 34 deletions(-)
>>>>
>>>> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
>>>> index d2fd064..6ad4a07 100644
>>>> --- a/drivers/media/rc/ir-lirc-codec.c
>>>> +++ b/drivers/media/rc/ir-lirc-codec.c
>>>> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>>  	unsigned int *txbuf; /* buffer with values to transmit */
>>>>  	ssize_t ret = -EINVAL;
>>>>  	size_t count;
>>>> +	ktime_t start;
>>>> +	s64 towait;
>>>> +	unsigned int duration = 0; /* signal duration in us */
>>>> +	int i;
>>>> +
>>>> +	start = ktime_get();
>>>>  
>>>>  	lirc = lirc_get_pdata(file);
>>>>  	if (!lirc)
>>>> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>>  		goto out;
>>>>  	}
>>>>  
>>>> -	if (dev->tx_ir)
>>>> -		ret = dev->tx_ir(dev, txbuf, count);
>>>> +	if (!dev->tx_ir) {
>>>> +		ret = -ENOSYS;
>>>> +		goto out;
>>>> +	}
>>>> +
>>>> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
>>>> +	if (ret < 0)
>>>> +		goto out;
>>>> +
>>>> +	for (i = 0; i < ret; i++)
>>>> +		duration += txbuf[i];
>>>>  
>>>> -	if (ret > 0)
>>>> -		ret *= sizeof(unsigned);
>>>> +	ret *= sizeof(unsigned int);
>>>> +
>>>> +	/*
>>>> +	 * The lircd gap calculation expects the write function to
>>>> +	 * wait for the actual IR signal to be transmitted before
>>>> +	 * returning.
>>>> +	 */
>>>> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
>>>> +	if (towait > 0) {
>>>> +		set_current_state(TASK_INTERRUPTIBLE);
>>>> +		schedule_timeout(usecs_to_jiffies(towait));
>>>> +	}
>>>>  
>>>>  out:
>>>
>>> You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
>>> sense for some devices. However you haven't updated winbond-cir.c which
>>> does two things:
>>>
>>> 1) Modifies the txbuf (which is now used after transmit)
>>> 2) Does the sleeping already since it blocks on the device to complete.
>>>
>>> Surely if the driver can block on the device to complete then that is 
>>> better than sleeping; there might some difference due to rounding and 
>>> clock skew.
>>>
>>> In addition to winbond-cir, iguanair suffer from the same problem. There
>>> might be others.
>>
>> That's likely my fault: I was waiting for Jarod's review on this patch,
>> with didn't happen, likely because he is too busy with some other stuff.
>> Both winbond and iguanair drivers went after David's patch.
>>
>> Feel free to send me a patch fixing it there.
>>
>>> Could we have a flag in rc_dev to signify whether a driver blocks on
>>> completion of a transmit and only sleep here if it is not set?
>>>
>>> e.g. rc_dev.tx_blocks_until_complete
>>>
>>> The wording could be improved.
>>>
>>> Another alternative would be if the drivers provided a 
>>> "wait_for_tx_to_complete()" function. If they can provided that; using 
>>> that it would be possible to implement O_NONBLOCK and sync.
>>
>> Seems fine on my eyes. It may avoid code duplication if you pass the fd 
>> flags to the lirc call, and add a code there that will wait for complete, 
>> if the device was not opened in block mode.
> 
> I think a future rc-core native TX API should behave like a write() on a
> network socket does.
> 
> That is, a write on a rc device opened with O_NONBLOCK will either
> succeed immediately (i.e. write data to buffers for further processing)
> or return EAGAIN.  A write on a non-O_NONBLOCK device will either write
> the data to buffer space and return or wait for more space to be
> available. No waiting for the data to actually leave the "device" (NIC
> or IR transmitter) is done by the write() call.
> 
> The "gap calculation" that lirc wants to do based on the time a write()
> takes to complete is quite non-unixy in my eyes and seems bogus.
> 
> If a user-space program wants a very specific and deterministic
> behaviour, eg. wrt gaps...it should just add it to the TX data.
> 
> I.e. if you want to TX command "A", wait 150ms, TX command "B", then
> instead of doing:
> 
> write(A); sleep(150ms); write(B);
> 
> the app should do:
> 
> write(A + 150ms silence + B);
> 
> The same goes for e.g. trailing silences after commands, etc...

That makes sense to me, but we need to not break existing userspace
applications with new improvements.

Yeah, a better API is needed to not only allow sending pulse/space/waiting
times to IR TX, but also sending real keystrokes, like:

echo "A" > /dev/<some rc device>

Still, I'm not sure if we should create a "150 ms silence" keystroke. That
doesn't sound linux style to me.

The Linux way would be:

fputs("A", fp);
fflush(fp);
usleep(150000);
fputs("B", fp);

That's close to what is done on term apps like minicom.

Ok, currently, all drivers have only "raw" TX. Yet, HDMI CEC provides
a way to receive/send IR commands from/to the TV set. So, I think we'll
have soon some drivers that only work on 'non-raw' TX mode.

So, IMO, it makes sense to have a "high end" API that accepts
writing keystrokes like above, working with both "raw drivers"
using some kernel IR protocol encoders, and with devices that can
accept "processed" keystrokes, like HDMI CEC.

The lirc interface may not be the right device for such usage,
if changing it would break support for existing devices.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-20 22:02     ` Mauro Carvalho Chehab
@ 2012-08-20 22:10       ` Devin Heitmueller
  2012-08-21 19:44         ` David Härdeman
  2012-08-21 12:55       ` Sean Young
  2012-08-21 19:42       ` David Härdeman
  2 siblings, 1 reply; 11+ messages in thread
From: Devin Heitmueller @ 2012-08-20 22:10 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: David Härdeman, Sean Young, Jarod Wilson, linux-media

On Mon, Aug 20, 2012 at 6:02 PM, Mauro Carvalho Chehab
<mchehab@redhat.com> wrote:
> So, IMO, it makes sense to have a "high end" API that accepts
> writing keystrokes like above, working with both "raw drivers"
> using some kernel IR protocol encoders, and with devices that can
> accept "processed" keystrokes, like HDMI CEC.

It might also make sense to have a third mode for devices that support
high level protocols such as RC5/NEC but you want to leverage the very
large existing LIRC database of remote controls.  The device would
advertise all the modes it supports (RC5/NEC/RC6/whatever), and from
there it can accept the actual RC codes instead of a raw waveform.

I recognize that this is case that falls in between the two models
proposed, but there are devices that fall into this category.  The
alternative for those devices would be for LIRC to convert the RC5
code into a raw waveform, send the raw waveform to the kernel, and
then the driver convert it back into a code, which would be quite
messy since it would have to figure out what RC format it was
originally in.  It would be much better if LIRC could just send the
RC5 code directly into the kernel.

Devin

-- 
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-20 22:02     ` Mauro Carvalho Chehab
  2012-08-20 22:10       ` Devin Heitmueller
@ 2012-08-21 12:55       ` Sean Young
  2012-08-21 19:55         ` David Härdeman
  2012-08-21 19:42       ` David Härdeman
  2 siblings, 1 reply; 11+ messages in thread
From: Sean Young @ 2012-08-21 12:55 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: David Härdeman, Jarod Wilson, linux-media

On Mon, Aug 20, 2012 at 07:02:47PM -0300, Mauro Carvalho Chehab wrote:
> Em 20-08-2012 18:36, David Härdeman escreveu:
> > On Thu, Aug 16, 2012 at 08:12:34PM -0300, Mauro Carvalho Chehab wrote:
> >> Em 16-08-2012 19:15, Sean Young escreveu:
> >>> Could we have a flag in rc_dev to signify whether a driver blocks on
> >>> completion of a transmit and only sleep here if it is not set?
> >>>
> >>> e.g. rc_dev.tx_blocks_until_complete
> >>>
> >>> The wording could be improved.
> >>>
> >>> Another alternative would be if the drivers provided a 
> >>> "wait_for_tx_to_complete()" function. If they can provided that; using 
> >>> that it would be possible to implement O_NONBLOCK and sync.
> >>
> >> Seems fine on my eyes. It may avoid code duplication if you pass the fd 
> >> flags to the lirc call, and add a code there that will wait for complete, 
> >> if the device was not opened in block mode.
> > 
> > I think a future rc-core native TX API should behave like a write() on a
> > network socket does.
> > 
> > That is, a write on a rc device opened with O_NONBLOCK will either
> > succeed immediately (i.e. write data to buffers for further processing)
> > or return EAGAIN.  A write on a non-O_NONBLOCK device will either write
> > the data to buffer space and return or wait for more space to be
> > available. No waiting for the data to actually leave the "device" (NIC
> > or IR transmitter) is done by the write() call.

The waiting for the data to leave the device could be enforced by opening
with O_SYNC or fsync(). I agree with O_NONBLOCK being better for blocking
on outgoing buffer space.

We could also have a kernel space write buffer (kfifo?) which the device 
driver works its way through; user space would just have to make sure
the buffer doesn't deplete, but there would be no limit on the IR signal
including silences. In that way the timing is entirely done in kernel 
space and no need for awkward sleeps and crossing of fingers.

> > 
> > The "gap calculation" that lirc wants to do based on the time a write()
> > takes to complete is quite non-unixy in my eyes and seems bogus.

Yes. Also if a signal arrives then the the user space program has no idea 
where it is at.

> > If a user-space program wants a very specific and deterministic
> > behaviour, eg. wrt gaps...it should just add it to the TX data.
> > 
> > I.e. if you want to TX command "A", wait 150ms, TX command "B", then
> > instead of doing:
> > 
> > write(A); sleep(150ms); write(B);
> > 
> > the app should do:
> > 
> > write(A + 150ms silence + B);
> > 
> > The same goes for e.g. trailing silences after commands, etc...
> 
> That makes sense to me, but we need to not break existing userspace
> applications with new improvements.
> 
> Yeah, a better API is needed to not only allow sending pulse/space/waiting
> times to IR TX, but also sending real keystrokes, like:
> 
> echo "A" > /dev/<some rc device>
>
> Still, I'm not sure if we should create a "150 ms silence" keystroke. That
> doesn't sound linux style to me.
> 
> The Linux way would be:
> 
> fputs("A", fp);
> fflush(fp);
> usleep(150000);
> fputs("B", fp);
> 
> That's close to what is done on term apps like minicom.
> 
> Ok, currently, all drivers have only "raw" TX. Yet, HDMI CEC provides
> a way to receive/send IR commands from/to the TV set. So, I think we'll
> have soon some drivers that only work on 'non-raw' TX mode.
> 
> So, IMO, it makes sense to have a "high end" API that accepts
> writing keystrokes like above, working with both "raw drivers"
> using some kernel IR protocol encoders, and with devices that can
> accept "processed" keystrokes, like HDMI CEC.

For devices that only accept "raw" IR, it can be done in user space.

I agree the existing user space tools aren't sufficient; it would be nice 
to have:

1. Something to send IR codes (NEC, RC-5, etc)
2. Something send a file with "pulse %d\nspace %d"..., i.e. the output mode2
3. Something to send keystrokes read from the rc_keymaps

I've written the first two for my own usage and it really doesn't need
moving into the kernel, IMHO.

> The lirc interface may not be the right device for such usage,
> if changing it would break support for existing devices.

It would be great to obsolete that interface. Could reading raw IR be
merged with the input interface?


Sean

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-20 22:02     ` Mauro Carvalho Chehab
  2012-08-20 22:10       ` Devin Heitmueller
  2012-08-21 12:55       ` Sean Young
@ 2012-08-21 19:42       ` David Härdeman
  2 siblings, 0 replies; 11+ messages in thread
From: David Härdeman @ 2012-08-21 19:42 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Sean Young, Jarod Wilson, linux-media

On Mon, Aug 20, 2012 at 07:02:47PM -0300, Mauro Carvalho Chehab wrote:
>Em 20-08-2012 18:36, David Härdeman escreveu:
>> On Thu, Aug 16, 2012 at 08:12:34PM -0300, Mauro Carvalho Chehab wrote:
>>> Em 16-08-2012 19:15, Sean Young escreveu:
>>>>  
>>>>> The lirc TX functionality expects the process which writes (TX) data to
>>>>> the lirc dev to sleep until the actual data has been transmitted by the
>>>>> hardware.
>>>>>
>>>>> Since the same timeout calculation is duplicated in more than one driver
>>>>> (and would have to be duplicated in even more drivers as they gain TX
>>>>> support), it makes sense to move this timeout calculation to the lirc
>>>>> layer instead.
>>>>>
>>>>> At the same time, centralize some of the sanity checks.
>>>>>
>>>>> Signed-off-by: David Härdeman <david@hardeman.nu>
>>>>> Cc: Jarod Wilson <jwilson@redhat.com>
>>>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>>>>> ---
>>>>>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>>>>>  drivers/media/rc/mceusb.c        | 18 ------------------
>>>>>  drivers/media/rc/rc-loopback.c   | 12 ------------
>>>>>  3 files changed, 29 insertions(+), 34 deletions(-)
>>>>>
>>>>> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
>>>>> index d2fd064..6ad4a07 100644
>>>>> --- a/drivers/media/rc/ir-lirc-codec.c
>>>>> +++ b/drivers/media/rc/ir-lirc-codec.c
>>>>> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>>>  	unsigned int *txbuf; /* buffer with values to transmit */
>>>>>  	ssize_t ret = -EINVAL;
>>>>>  	size_t count;
>>>>> +	ktime_t start;
>>>>> +	s64 towait;
>>>>> +	unsigned int duration = 0; /* signal duration in us */
>>>>> +	int i;
>>>>> +
>>>>> +	start = ktime_get();
>>>>>  
>>>>>  	lirc = lirc_get_pdata(file);
>>>>>  	if (!lirc)
>>>>> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>>>>  		goto out;
>>>>>  	}
>>>>>  
>>>>> -	if (dev->tx_ir)
>>>>> -		ret = dev->tx_ir(dev, txbuf, count);
>>>>> +	if (!dev->tx_ir) {
>>>>> +		ret = -ENOSYS;
>>>>> +		goto out;
>>>>> +	}
>>>>> +
>>>>> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
>>>>> +	if (ret < 0)
>>>>> +		goto out;
>>>>> +
>>>>> +	for (i = 0; i < ret; i++)
>>>>> +		duration += txbuf[i];
>>>>>  
>>>>> -	if (ret > 0)
>>>>> -		ret *= sizeof(unsigned);
>>>>> +	ret *= sizeof(unsigned int);
>>>>> +
>>>>> +	/*
>>>>> +	 * The lircd gap calculation expects the write function to
>>>>> +	 * wait for the actual IR signal to be transmitted before
>>>>> +	 * returning.
>>>>> +	 */
>>>>> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
>>>>> +	if (towait > 0) {
>>>>> +		set_current_state(TASK_INTERRUPTIBLE);
>>>>> +		schedule_timeout(usecs_to_jiffies(towait));
>>>>> +	}
>>>>>  
>>>>>  out:
>>>>
>>>> You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
>>>> sense for some devices. However you haven't updated winbond-cir.c which
>>>> does two things:
>>>>
>>>> 1) Modifies the txbuf (which is now used after transmit)
>>>> 2) Does the sleeping already since it blocks on the device to complete.
>>>>
>>>> Surely if the driver can block on the device to complete then that is 
>>>> better than sleeping; there might some difference due to rounding and 
>>>> clock skew.
>>>>
>>>> In addition to winbond-cir, iguanair suffer from the same problem. There
>>>> might be others.
>>>
>>> That's likely my fault: I was waiting for Jarod's review on this patch,
>>> with didn't happen, likely because he is too busy with some other stuff.
>>> Both winbond and iguanair drivers went after David's patch.
>>>
>>> Feel free to send me a patch fixing it there.
>>>
>>>> Could we have a flag in rc_dev to signify whether a driver blocks on
>>>> completion of a transmit and only sleep here if it is not set?
>>>>
>>>> e.g. rc_dev.tx_blocks_until_complete
>>>>
>>>> The wording could be improved.
>>>>
>>>> Another alternative would be if the drivers provided a 
>>>> "wait_for_tx_to_complete()" function. If they can provided that; using 
>>>> that it would be possible to implement O_NONBLOCK and sync.
>>>
>>> Seems fine on my eyes. It may avoid code duplication if you pass the fd 
>>> flags to the lirc call, and add a code there that will wait for complete, 
>>> if the device was not opened in block mode.
>> 
>> I think a future rc-core native TX API should behave like a write() on a
>> network socket does.
>> 
>> That is, a write on a rc device opened with O_NONBLOCK will either
>> succeed immediately (i.e. write data to buffers for further processing)
>> or return EAGAIN.  A write on a non-O_NONBLOCK device will either write
>> the data to buffer space and return or wait for more space to be
>> available. No waiting for the data to actually leave the "device" (NIC
>> or IR transmitter) is done by the write() call.
>> 
>> The "gap calculation" that lirc wants to do based on the time a write()
>> takes to complete is quite non-unixy in my eyes and seems bogus.
>> 
>> If a user-space program wants a very specific and deterministic
>> behaviour, eg. wrt gaps...it should just add it to the TX data.
>> 
>> I.e. if you want to TX command "A", wait 150ms, TX command "B", then
>> instead of doing:
>> 
>> write(A); sleep(150ms); write(B);
>> 
>> the app should do:
>> 
>> write(A + 150ms silence + B);
>> 
>> The same goes for e.g. trailing silences after commands, etc...
>
>That makes sense to me, but we need to not break existing userspace
>applications with new improvements.

Agreed. But that is what the patch aimed to do. The "timeout" was moved
to the lirc code and out of the drivers. Then a new API could call the 
drivers directly, without any timeout, while the lirc layer emulates the
old behavior.

>Yeah, a better API is needed to not only allow sending pulse/space/waiting
>times to IR TX, but also sending real keystrokes, like:
>
>echo "A" > /dev/<some rc device>
>
>Still, I'm not sure if we should create a "150 ms silence" keystroke. That
>doesn't sound linux style to me.
>
>The Linux way would be:
>
>fputs("A", fp);
>fflush(fp);
>usleep(150000);
>fputs("B", fp);
>
>That's close to what is done on term apps like minicom.

Sorry, I was being too terse. What I meant with "A" and "B" was actually
"sequence of pulse/space timings corresponding to IR command A/B".

So, if lircd used to do this:

	unsigned cmd_A[] = { 500, 1000, 500, 500 ...};
	unsigned cmd_B[] = { 500, 1000, 500, 1000 ...};

	write_pulsespace(cmd_A, fp);
	usleep(150000);
	write_pulsespace(cmd_B, fp);

it should instead (with a new, non-lirc API) do:

	unsigned cmd_A[] = { 500, 1000, 500, 500 ...};
	unsigned cmd_B[] = { 500, 1000, 500, 1000 ...};

	write_pulsespace(cmd_A, fp);
	write_space(150000, fp);
	write_pulsespace(cmd_B, fp);

And not care a bit about any "gap calculations".

The result would be that the lircd daemon can go about it's business and
that the TX hardware is guaranteed to be busy for the duration it takes
to send the "A" command, silent for 150ms, and yet again busy for the
duration it takes to send the "B" command.

>Ok, currently, all drivers have only "raw" TX. Yet, HDMI CEC provides
>a way to receive/send IR commands from/to the TV set. So, I think we'll
>have soon some drivers that only work on 'non-raw' TX mode.
>
>So, IMO, it makes sense to have a "high end" API that accepts
>writing keystrokes like above, working with both "raw drivers"
>using some kernel IR protocol encoders, and with devices that can
>accept "processed" keystrokes, like HDMI CEC.

Agreed.

>The lirc interface may not be the right device for such usage,
>if changing it would break support for existing devices.

No, the lirc interface is unlikely to be what we want. Instead, I expect
the future API to be modelled along the lines of:

	unsigned cmd_A[] = { 500, 1000, 500, 500 ...};

	fd = open("/dev/some_rc_dev");
	ioctl(fd, RCIOCGTXTYPE, &type);

	switch (type) {
	case RC_DRIVER_SCANCODE:
		write_cmd(KEY_A, fd);
		break;
	case RC_DRIVER_IR_RAW:
		write_pulsespace(cmd_A, fd);
		break;
	...
	default:
		error("Unknown device type\n");
	}

(Some details left out...the type above is probably going to have to be
a bitmask for example).

The lirc layer could trivially be provided by a compat driver (as now)
which supports doing the right thing on the right kinds of hardware
(i.e. not support e.g. HDMI-CEC with keystrokes).


-- 
David Härdeman

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-20 22:10       ` Devin Heitmueller
@ 2012-08-21 19:44         ` David Härdeman
  0 siblings, 0 replies; 11+ messages in thread
From: David Härdeman @ 2012-08-21 19:44 UTC (permalink / raw)
  To: Devin Heitmueller
  Cc: Mauro Carvalho Chehab, Sean Young, Jarod Wilson, linux-media

On Mon, Aug 20, 2012 at 06:10:16PM -0400, Devin Heitmueller wrote:
>On Mon, Aug 20, 2012 at 6:02 PM, Mauro Carvalho Chehab
><mchehab@redhat.com> wrote:
>> So, IMO, it makes sense to have a "high end" API that accepts
>> writing keystrokes like above, working with both "raw drivers"
>> using some kernel IR protocol encoders, and with devices that can
>> accept "processed" keystrokes, like HDMI CEC.
>
>It might also make sense to have a third mode for devices that support
>high level protocols such as RC5/NEC but you want to leverage the very
>large existing LIRC database of remote controls.  The device would
>advertise all the modes it supports (RC5/NEC/RC6/whatever), and from
>there it can accept the actual RC codes instead of a raw waveform.

That should be pretty trivial with the API I suggested - i.e. that
userspace is expected to do an ioctl first to get the bitmask of
supported modes. This would just be another TX mode.


-- 
David Härdeman

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-21 12:55       ` Sean Young
@ 2012-08-21 19:55         ` David Härdeman
  0 siblings, 0 replies; 11+ messages in thread
From: David Härdeman @ 2012-08-21 19:55 UTC (permalink / raw)
  To: Sean Young; +Cc: Mauro Carvalho Chehab, Jarod Wilson, linux-media

On Tue, Aug 21, 2012 at 01:55:12PM +0100, Sean Young wrote:
>On Mon, Aug 20, 2012 at 07:02:47PM -0300, Mauro Carvalho Chehab wrote:
>> Em 20-08-2012 18:36, David Härdeman escreveu:
>> > On Thu, Aug 16, 2012 at 08:12:34PM -0300, Mauro Carvalho Chehab wrote:
>> >> Em 16-08-2012 19:15, Sean Young escreveu:
>> >>> Could we have a flag in rc_dev to signify whether a driver blocks on
>> >>> completion of a transmit and only sleep here if it is not set?
>> >>>
>> >>> e.g. rc_dev.tx_blocks_until_complete
>> >>>
>> >>> The wording could be improved.
>> >>>
>> >>> Another alternative would be if the drivers provided a 
>> >>> "wait_for_tx_to_complete()" function. If they can provided that; using 
>> >>> that it would be possible to implement O_NONBLOCK and sync.
>> >>
>> >> Seems fine on my eyes. It may avoid code duplication if you pass the fd 
>> >> flags to the lirc call, and add a code there that will wait for complete, 
>> >> if the device was not opened in block mode.
>> > 
>> > I think a future rc-core native TX API should behave like a write() on a
>> > network socket does.
>> > 
>> > That is, a write on a rc device opened with O_NONBLOCK will either
>> > succeed immediately (i.e. write data to buffers for further processing)
>> > or return EAGAIN.  A write on a non-O_NONBLOCK device will either write
>> > the data to buffer space and return or wait for more space to be
>> > available. No waiting for the data to actually leave the "device" (NIC
>> > or IR transmitter) is done by the write() call.
>
>The waiting for the data to leave the device could be enforced by opening
>with O_SYNC or fsync(). I agree with O_NONBLOCK being better for blocking
>on outgoing buffer space.

I don't think we should support O_SYNC at all unless there is a
compelling use-case for it. I seriously doubt there is one. A rc device
has more in common with a socket() than a open():ed file which resides
on a harddisk.

The O_NONBLOCK case is useful for e.g. a future lircd which uses some
kind of epoll() event loop to write TX data, read RX data and to
send/receive commands to/from userspace.

The non-O_NONBLOCK case is useful to e.g. a debug command line program
which does a blocking write and returns once the entire TX data stream
has been passed to the kernel (eg some kind of rc_tx tool which could be
used in scripts).

>We could also have a kernel space write buffer (kfifo?) which the device 
>driver works its way through; user space would just have to make sure
>the buffer doesn't deplete, but there would be no limit on the IR signal
>including silences. In that way the timing is entirely done in kernel 
>space and no need for awkward sleeps and crossing of fingers.

That is what I've proposed (in the patchset I've already sent, a kfifo
is used for TX and trailing silences and/or inter-command silences can
be encoded in the TX data itself).

>> The lirc interface may not be the right device for such usage,
>> if changing it would break support for existing devices.
>
>It would be great to obsolete that interface. Could reading raw IR be
>merged with the input interface?

No, it should be done using a separate RC-specific device...because we
should support multiple input devices per RC device and not pollute the
input subsystem with rc specifics.

-- 
David Härdeman

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-16 22:15 [media] rc-core: move timeout and checks to lirc Sean Young
  2012-08-16 23:12 ` Mauro Carvalho Chehab
@ 2012-08-24 22:16 ` David Härdeman
  2012-08-24 23:19   ` Sean Young
  1 sibling, 1 reply; 11+ messages in thread
From: David Härdeman @ 2012-08-24 22:16 UTC (permalink / raw)
  To: Sean Young; +Cc: Jarod Wilson, linux-media

On Thu, Aug 16, 2012 at 11:15:14PM +0100, Sean Young wrote:
> 
>> The lirc TX functionality expects the process which writes (TX) data to
>> the lirc dev to sleep until the actual data has been transmitted by the
>> hardware.
>> 
>> Since the same timeout calculation is duplicated in more than one driver
>> (and would have to be duplicated in even more drivers as they gain TX
>> support), it makes sense to move this timeout calculation to the lirc
>> layer instead.
>> 
>> At the same time, centralize some of the sanity checks.
>> 
>> Signed-off-by: David Härdeman <david@hardeman.nu>
>> Cc: Jarod Wilson <jwilson@redhat.com>
>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>> ---
>>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
>>  drivers/media/rc/mceusb.c        | 18 ------------------
>>  drivers/media/rc/rc-loopback.c   | 12 ------------
>>  3 files changed, 29 insertions(+), 34 deletions(-)
>> 
>> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
>> index d2fd064..6ad4a07 100644
>> --- a/drivers/media/rc/ir-lirc-codec.c
>> +++ b/drivers/media/rc/ir-lirc-codec.c
>> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>  	unsigned int *txbuf; /* buffer with values to transmit */
>>  	ssize_t ret = -EINVAL;
>>  	size_t count;
>> +	ktime_t start;
>> +	s64 towait;
>> +	unsigned int duration = 0; /* signal duration in us */
>> +	int i;
>> +
>> +	start = ktime_get();
>>  
>>  	lirc = lirc_get_pdata(file);
>>  	if (!lirc)
>> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>>  		goto out;
>>  	}
>>  
>> -	if (dev->tx_ir)
>> -		ret = dev->tx_ir(dev, txbuf, count);
>> +	if (!dev->tx_ir) {
>> +		ret = -ENOSYS;
>> +		goto out;
>> +	}
>> +
>> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
>> +	if (ret < 0)
>> +		goto out;
>> +
>> +	for (i = 0; i < ret; i++)
>> +		duration += txbuf[i];
>>  
>> -	if (ret > 0)
>> -		ret *= sizeof(unsigned);
>> +	ret *= sizeof(unsigned int);
>> +
>> +	/*
>> +	 * The lircd gap calculation expects the write function to
>> +	 * wait for the actual IR signal to be transmitted before
>> +	 * returning.
>> +	 */
>> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
>> +	if (towait > 0) {
>> +		set_current_state(TASK_INTERRUPTIBLE);
>> +		schedule_timeout(usecs_to_jiffies(towait));
>> +	}
>>  
>>  out:
>
>You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
>sense for some devices. However you haven't updated winbond-cir.c which
>does two things:
>
>1) Modifies the txbuf (which is now used after transmit)
>2) Does the sleeping already since it blocks on the device to complete.

I'm not sure what issue 1) is?

Note that txstate is checked in wbcir_tx() at the beginning and the end.
The buf shouldn't be used after transmit...

>Surely if the driver can block on the device to complete then that is 
>better than sleeping; there might some difference due to rounding and 
>clock skew.

As noted in other mails, I actually think an asynchronous method is
better since it permits different approaches while a blocking TX method
forces that behavior.

Regards,
David


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [media] rc-core: move timeout and checks to lirc
  2012-08-24 22:16 ` David Härdeman
@ 2012-08-24 23:19   ` Sean Young
  0 siblings, 0 replies; 11+ messages in thread
From: Sean Young @ 2012-08-24 23:19 UTC (permalink / raw)
  To: David Härdeman; +Cc: Jarod Wilson, linux-media

On Sat, Aug 25, 2012 at 12:16:04AM +0200, David Härdeman wrote:
> On Thu, Aug 16, 2012 at 11:15:14PM +0100, Sean Young wrote:
> > 
> >> The lirc TX functionality expects the process which writes (TX) data to
> >> the lirc dev to sleep until the actual data has been transmitted by the
> >> hardware.
> >> 
> >> Since the same timeout calculation is duplicated in more than one driver
> >> (and would have to be duplicated in even more drivers as they gain TX
> >> support), it makes sense to move this timeout calculation to the lirc
> >> layer instead.
> >> 
> >> At the same time, centralize some of the sanity checks.
> >> 
> >> Signed-off-by: David Härdeman <david@hardeman.nu>
> >> Cc: Jarod Wilson <jwilson@redhat.com>
> >> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> >> ---
> >>  drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
> >>  drivers/media/rc/mceusb.c        | 18 ------------------
> >>  drivers/media/rc/rc-loopback.c   | 12 ------------
> >>  3 files changed, 29 insertions(+), 34 deletions(-)
> >> 
> >> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
> >> index d2fd064..6ad4a07 100644
> >> --- a/drivers/media/rc/ir-lirc-codec.c
> >> +++ b/drivers/media/rc/ir-lirc-codec.c
> >> @@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
> >>  	unsigned int *txbuf; /* buffer with values to transmit */
> >>  	ssize_t ret = -EINVAL;
> >>  	size_t count;
> >> +	ktime_t start;
> >> +	s64 towait;
> >> +	unsigned int duration = 0; /* signal duration in us */
> >> +	int i;
> >> +
> >> +	start = ktime_get();
> >>  
> >>  	lirc = lirc_get_pdata(file);
> >>  	if (!lirc)
> >> @@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
> >>  		goto out;
> >>  	}
> >>  
> >> -	if (dev->tx_ir)
> >> -		ret = dev->tx_ir(dev, txbuf, count);
> >> +	if (!dev->tx_ir) {
> >> +		ret = -ENOSYS;
> >> +		goto out;
> >> +	}
> >> +
> >> +	ret = dev->tx_ir(dev, txbuf, (u32)n);
> >> +	if (ret < 0)
> >> +		goto out;
> >> +
> >> +	for (i = 0; i < ret; i++)
> >> +		duration += txbuf[i];
> >>  
> >> -	if (ret > 0)
> >> -		ret *= sizeof(unsigned);
> >> +	ret *= sizeof(unsigned int);
> >> +
> >> +	/*
> >> +	 * The lircd gap calculation expects the write function to
> >> +	 * wait for the actual IR signal to be transmitted before
> >> +	 * returning.
> >> +	 */
> >> +	towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
> >> +	if (towait > 0) {
> >> +		set_current_state(TASK_INTERRUPTIBLE);
> >> +		schedule_timeout(usecs_to_jiffies(towait));
> >> +	}
> >>  
> >>  out:
> >
> >You've moved the sleeping out of the drivers to ir-lirc-codec, which makes
> >sense for some devices. However you haven't updated winbond-cir.c which
> >does two things:
> >
> >1) Modifies the txbuf (which is now used after transmit)
> >2) Does the sleeping already since it blocks on the device to complete.
> 
> I'm not sure what issue 1) is?
> 
> Note that txstate is checked in wbcir_tx() at the beginning and the end.
> The buf shouldn't be used after transmit...

Read your patch again (a few lines up from here). After transmit you use it 
to calculate how long you want to sleep.

Not sure how well you tested this, it crapped my machine every time without
that other patch I posted.

> >Surely if the driver can block on the device to complete then that is 
> >better than sleeping; there might some difference due to rounding and 
> >clock skew.
> 
> As noted in other mails, I actually think an asynchronous method is
> better since it permits different approaches while a blocking TX method
> forces that behavior.

Yep, but that's not ready yet.


Sean

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2012-08-24 23:19 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-16 22:15 [media] rc-core: move timeout and checks to lirc Sean Young
2012-08-16 23:12 ` Mauro Carvalho Chehab
2012-08-20 21:36   ` David Härdeman
2012-08-20 22:02     ` Mauro Carvalho Chehab
2012-08-20 22:10       ` Devin Heitmueller
2012-08-21 19:44         ` David Härdeman
2012-08-21 12:55       ` Sean Young
2012-08-21 19:55         ` David Härdeman
2012-08-21 19:42       ` David Härdeman
2012-08-24 22:16 ` David Härdeman
2012-08-24 23:19   ` Sean Young

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.