Re: [PATCH 4/4] pulse8-cec: sync configuration with adapter

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

 



On 08/19/2016 06:36 PM, Johan Fjeldtvedt wrote:
> When the configuration is changed, they are also written to the adapter.
> This allows the adapter to continue operating in autonomous mode with
> the same settings when it is disconnected from the driver (typically by
> going into suspend). For adapters with firmware version 2 or greater, the
> settings are also persisted in EEPROM.
> 
> A new module parameter is added to optionally also use the configuration
> already present in the adapter when it is connected. This option is
> enabled by default.
> 
> When a new configuration is written, the autonomous mode is
> automatically enabled. When the device is unconfigured, autonomous mode
> is disabled.
> 
> Signed-off-by: Johan Fjeldtvedt <jaffe1@xxxxxxxxx>
> ---
>  drivers/staging/media/pulse8-cec/pulse8-cec.c | 259 ++++++++++++++++++++++----
>  1 file changed, 221 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/staging/media/pulse8-cec/pulse8-cec.c b/drivers/staging/media/pulse8-cec/pulse8-cec.c
> index 4d20e72..531377a 100644
> --- a/drivers/staging/media/pulse8-cec/pulse8-cec.c
> +++ b/drivers/staging/media/pulse8-cec/pulse8-cec.c
> @@ -51,8 +51,11 @@ MODULE_DESCRIPTION("Pulse Eight HDMI CEC driver");
>  MODULE_LICENSE("GPL");
>  
>  static int debug;
> +static int persistent_config = 1;
>  module_param(debug, int, 0644);
> +module_param(persistent_config, int, 0644);
>  MODULE_PARM_DESC(debug, "debug level (0-1)");
> +MODULE_PARM_DESC(persitent_config, "read config from persitent memory (0-1)");

s/persitent/persistent/g

>  
>  enum pulse8_msgcodes {
>  	MSGCODE_NOTHING = 0,
> @@ -109,12 +112,16 @@ enum pulse8_msgcodes {
>  
>  #define DATA_SIZE 256
>  
> +#define PING_PERIOD	15 * HZ
> +
>  struct pulse8 {
>  	struct device *dev;
>  	struct serio *serio;
>  	struct cec_adapter *adap;
> +	unsigned int vers;
>  	struct completion cmd_done;
>  	struct work_struct work;
> +	struct delayed_work ping_eeprom_work;
>  	struct cec_msg rx_msg;
>  	u8 data[DATA_SIZE];
>  	unsigned int len;
> @@ -122,9 +129,15 @@ struct pulse8 {
>  	unsigned int idx;
>  	bool escape;
>  	bool started;
> +	struct mutex config_lock;
>  	struct mutex write_lock;
> +	bool config_pending;
> +	bool restoring_config;
> +	bool autonomous;
>  };
>  
> +static void pulse8_ping_eeprom_work_handler(struct work_struct *work);
> +
>  static void pulse8_irq_work_handler(struct work_struct *work)
>  {
>  	struct pulse8 *pulse8 =
> @@ -229,6 +242,7 @@ static void pulse8_disconnect(struct serio *serio)
>  	struct pulse8 *pulse8 = serio_get_drvdata(serio);
>  
>  	cec_unregister_adapter(pulse8->adap);
> +	cancel_delayed_work_sync(&pulse8->ping_eeprom_work);
>  	dev_info(&serio->dev, "disconnected\n");
>  	serio_close(serio);
>  	serio_set_drvdata(serio, NULL);
> @@ -309,14 +323,14 @@ static int pulse8_send_and_wait(struct pulse8 *pulse8,
>  	return err;
>  }
>  
> -static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio)
> +static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, struct cec_log_addrs *log_addrs, u16 *pa)
>  {
>  	u8 *data = pulse8->data + 1;
> -	unsigned int count = 0;
> -	unsigned int vers = 0;
>  	u8 cmd[2];
>  	int err;
>  
> +	pulse8->vers = 0;
> +
>  	cmd[0] = MSGCODE_PING;
>  	err = pulse8_send_and_wait(pulse8, cmd, 1,
>  				   MSGCODE_COMMAND_ACCEPTED, 0);
> @@ -326,10 +340,10 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio)
>  	if (err)
>  		return err;
>  
> -	vers = (data[0] << 8) | data[1];
> +	pulse8->vers = (data[0] << 8) | data[1];
>  
> -	dev_info(pulse8->dev, "Firmware version %04x\n", vers);
> -	if (vers < 2)
> +	dev_info(pulse8->dev, "Firmware version %04x\n", pulse8->vers);
> +	if (pulse8->vers < 2)
>  		return 0;
>  
>  	cmd[0] = MSGCODE_GET_BUILDDATE;
> @@ -346,37 +360,98 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio)
>  			 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
>  			 tm.tm_hour, tm.tm_min, tm.tm_sec);
>  	}
> +	if (err)
> +		return err;
>  
> -	do {
> -		if (count)
> -			msleep(500);
> -		cmd[0] = MSGCODE_SET_AUTO_ENABLED;
> -		cmd[1] = 0;
> -		err = pulse8_send_and_wait(pulse8, cmd, 2,
> -					   MSGCODE_COMMAND_ACCEPTED, 1);
> -		if (err && count == 0) {
> -			dev_info(pulse8->dev, "No Auto Enabled supported\n");
> -			return 0;
> -		}
> +	dev_dbg(pulse8->dev, "Persistent config:\n");
> +	cmd[0] = MSGCODE_GET_AUTO_ENABLED;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
> +	if (err)
> +		return err;
> +	pulse8->autonomous = data[0];
> +	dev_dbg(pulse8->dev, "Autonomous mode: %s",
> +		data[0] ? "on" : "off");
>  
> -		cmd[0] = MSGCODE_GET_AUTO_ENABLED;
> -		if (!err)
> -			err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
> -		if (!err && !data[0]) {
> -			cmd[0] = MSGCODE_WRITE_EEPROM;
> -			err = pulse8_send_and_wait(pulse8, cmd, 1,
> -						   MSGCODE_COMMAND_ACCEPTED, 1);
> -			cmd[0] = MSGCODE_GET_AUTO_ENABLED;
> -			if (!err)
> -				err = pulse8_send_and_wait(pulse8, cmd, 1,
> -							   cmd[0], 1);
> -		}
> -	} while (!err && data[0] && count++ < 5);
> +	cmd[0] = MSGCODE_GET_DEVICE_TYPE;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
> +	if (err)
> +		return err;
> +	log_addrs->primary_device_type[0] = data[0];
> +	dev_dbg(pulse8->dev, "Primary device type: %d\n", data[0]);
> +	switch (log_addrs->primary_device_type[0]) {
> +	case CEC_OP_PRIM_DEVTYPE_TV:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_RECORD:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_RECORD;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_TUNER:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TUNER;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_SWITCH:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
> +		break;
> +	case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_SPECIFIC;
> +		break;
> +	default:
> +		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
> +		dev_info(pulse8->dev, "Unknown Primary Device Type: %d\n",
> +			 log_addrs->primary_device_type[0]);

Add a break here.

> +	}
>  
> -	if (!err && data[0])
> -		err = -EIO;
> +	cmd[0] = MSGCODE_GET_LOGICAL_ADDRESS_MASK;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2);
> +	if (err)
> +		return err;
> +	log_addrs->log_addr_mask = (data[0] << 8) | data[1];
> +	dev_dbg(pulse8->dev, "Logical address ACK mask: %x\n", log_addrs->log_addr_mask);
> +	if (log_addrs->log_addr_mask)
> +		log_addrs->num_log_addrs = 1;
>  
> -	return err;
> +	cmd[0] = MSGCODE_GET_PHYSICAL_ADDRESS;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
> +	if (err)
> +		return err;
> +	*pa = (data[0] << 8) | data[1];
> +	dev_dbg(pulse8->dev, "Physical address: %x.%x.%x.%x\n", cec_phys_addr_exp(*pa));
> +
> +	cmd[0] = MSGCODE_GET_HDMI_VERSION;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
> +	if (err)
> +		return err;
> +	log_addrs->cec_version = data[0];
> +	dev_dbg(pulse8->dev, "CEC version: %d\n", log_addrs->cec_version);
> +
> +	cmd[0] = MSGCODE_GET_OSD_NAME;
> +	err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0);
> +	if (err)
> +		return err;
> +	strncpy(log_addrs->osd_name, data, 13);
> +	dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name);
> +
> +	return 0;
> +}
> +
> +static int pulse8_apply_persistent_config(struct pulse8 *pulse8, struct cec_log_addrs *log_addrs, u16 pa)
> +{
> +	int err;
> +
> +	err = cec_s_log_addrs(pulse8->adap, log_addrs, false);
> +	if (err)
> +		return err;
> +
> +	cec_s_phys_addr(pulse8->adap, pa, false);
> +	if (err)
> +		return err;
> +
> +	return 0;
>  }
>  
>  static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable)
> @@ -396,9 +471,11 @@ static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
>  {
>  	struct pulse8 *pulse8 = adap->priv;
>  	u16 mask = 0;
> -	u8 cmd[3];
> -	int err;
> +	u16 pa = adap->phys_addr;
> +	u8 cmd[16];
> +	int err = 0;
>  
> +	mutex_lock(&pulse8->config_lock);
>  	if (log_addr != CEC_LOG_ADDR_INVALID)
>  		mask = 1 << log_addr;
>  	cmd[0] = MSGCODE_SET_ACK_MASK;
> @@ -406,8 +483,72 @@ static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
>  	cmd[2] = mask & 0xff;
>  	err = pulse8_send_and_wait(pulse8, cmd, 3,
>  				   MSGCODE_COMMAND_ACCEPTED, 0);
> -	if (mask == 0)
> -		return 0;
> +	if ((err && mask != 0) || pulse8->restoring_config)
> +		goto unlock;
> +
> +	cmd[0] = MSGCODE_SET_AUTO_ENABLED;
> +	cmd[1] = log_addr == CEC_LOG_ADDR_INVALID ? 0 : 1;
> +	err = pulse8_send_and_wait(pulse8, cmd, 2,
> +				   MSGCODE_COMMAND_ACCEPTED, 0);
> +	if (err)
> +		goto unlock;
> +	pulse8->autonomous = cmd[1];
> +	if (log_addr == CEC_LOG_ADDR_INVALID)
> +		goto unlock;
> +
> +	cmd[0] = MSGCODE_SET_DEVICE_TYPE;
> +	cmd[1] = adap->log_addrs.primary_device_type[0];
> +	err = pulse8_send_and_wait(pulse8, cmd, 2,
> +				   MSGCODE_COMMAND_ACCEPTED, 0);
> +	if (err)
> +		goto unlock;
> +
> +	cmd[0] = MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS;
> +	cmd[1] = log_addr;
> +	err = pulse8_send_and_wait(pulse8, cmd, 2,
> +				   MSGCODE_COMMAND_ACCEPTED, 0);
> +	if (err)
> +		goto unlock;
> +
> +	cmd[0] = MSGCODE_SET_PHYSICAL_ADDRESS;
> +	cmd[1] = pa >> 8;
> +	cmd[2] = pa & 0xff;
> +	err = pulse8_send_and_wait(pulse8, cmd, 3,
> +				   MSGCODE_COMMAND_ACCEPTED, 0);
> +	if (err)
> +		goto unlock;
> +
> +	cmd[0] = MSGCODE_SET_HDMI_VERSION;
> +	cmd[1] = adap->log_addrs.cec_version;
> +	err = pulse8_send_and_wait(pulse8, cmd, 2,
> +				   MSGCODE_COMMAND_ACCEPTED, 0);
> +	if (err)
> +		goto unlock;
> +
> +	if (adap->log_addrs.osd_name[0]) {
> +		size_t osd_len = strlen(adap->log_addrs.osd_name);
> +		char *osd_str = cmd + 1;
> +
> +		cmd[0] = MSGCODE_SET_OSD_NAME;
> +		strncpy(cmd + 1, adap->log_addrs.osd_name, 13);
> +		if (osd_len < 4) {
> +			memset(osd_str + osd_len, ' ', 4 - osd_len);
> +			osd_len = 4;
> +			osd_str[osd_len] = '\0';
> +			strcpy(adap->log_addrs.osd_name, osd_str);
> +		}
> +		err = pulse8_send_and_wait(pulse8, cmd, 1 + osd_len,
> +					   MSGCODE_COMMAND_ACCEPTED, 0);
> +		if (err)
> +			goto unlock;
> +	}
> +
> +  unlock:
> +	if (pulse8->restoring_config)
> +		pulse8->restoring_config = false;
> +	else
> +		pulse8->config_pending = true;
> +	mutex_unlock(&pulse8->config_lock);
>  	return err;
>  }
>  
> @@ -469,6 +610,8 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
>  		CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL;
>  	struct pulse8 *pulse8;
>  	int err = -ENOMEM;
> +	struct cec_log_addrs log_addrs = {};
> +	u16 pa;
>  
>  	pulse8 = kzalloc(sizeof(*pulse8), GFP_KERNEL);
>  
> @@ -486,12 +629,14 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
>  	serio_set_drvdata(serio, pulse8);
>  	INIT_WORK(&pulse8->work, pulse8_irq_work_handler);
>  	mutex_init(&pulse8->write_lock);
> +	mutex_init(&pulse8->config_lock);
> +	pulse8->config_pending = false;
>  
>  	err = serio_open(serio, drv);
>  	if (err)
>  		goto delete_adap;
>  
> -	err = pulse8_setup(pulse8, serio);
> +	err = pulse8_setup(pulse8, serio, &log_addrs, &pa);
>  	if (err)
>  		goto close_serio;
>  
> @@ -500,6 +645,17 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
>  		goto close_serio;
>  
>  	pulse8->dev = &pulse8->adap->devnode.dev;
> +
> +	if (persistent_config && pulse8->autonomous) {
> +		err = pulse8_apply_persistent_config(pulse8, &log_addrs, pa);
> +		if (err)
> +			goto close_serio;
> +		pulse8->restoring_config = true;
> +	}
> +
> +	INIT_DELAYED_WORK(&pulse8->ping_eeprom_work, pulse8_ping_eeprom_work_handler);
> +	schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
> +
>  	return 0;
>  
>  close_serio:
> @@ -512,6 +668,33 @@ free_device:
>  	return err;
>  }
>  
> +static void pulse8_ping_eeprom_work_handler(struct work_struct *work)
> +{
> +	struct pulse8 *pulse8 =
> +		container_of(work, struct pulse8, ping_eeprom_work.work);
> +	u8 cmd;
> +
> +	schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
> +	cmd = MSGCODE_PING;
> +	pulse8_send_and_wait(pulse8, &cmd, 1,
> +			     MSGCODE_COMMAND_ACCEPTED, 0);
> +
> +	if (pulse8->vers < 2)
> +		return;
> +
> +	mutex_lock(&pulse8->config_lock);
> +	if (pulse8->config_pending && persistent_config) {
> +		dev_dbg(pulse8->dev, "writing pending config to EEPROM\n");
> +		cmd = MSGCODE_WRITE_EEPROM;
> +		if (pulse8_send_and_wait(pulse8, &cmd, 1,
> +					 MSGCODE_COMMAND_ACCEPTED, 0))
> +			dev_info(pulse8->dev, "failed to write pending config to EEPROM\n");
> +		else
> +			pulse8->config_pending = false;
> +	}
> +	mutex_unlock(&pulse8->config_lock);
> +}
> +
>  static struct serio_device_id pulse8_serio_ids[] = {
>  	{
>  		.type	= SERIO_RS232,
> 

Regards,

	Hans
--
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