diff options
Diffstat (limited to 'drivers/media/cec')
-rw-r--r-- | drivers/media/cec/cec-adap.c | 52 | ||||
-rw-r--r-- | drivers/media/cec/cec-api.c | 20 | ||||
-rw-r--r-- | drivers/media/cec/cec-core.c | 5 | ||||
-rw-r--r-- | drivers/media/cec/cec-notifier.c | 5 | ||||
-rw-r--r-- | drivers/media/cec/cec-pin.c | 10 |
5 files changed, 69 insertions, 23 deletions
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 5ef7daeb8cbd..6c95dc471d4c 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -319,6 +319,8 @@ static void cec_post_state_event(struct cec_adapter *adap) ev.state_change.phys_addr = adap->phys_addr; ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + ev.state_change.have_conn_info = + adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR; cec_queue_event(adap, &ev); } @@ -378,7 +380,8 @@ static void cec_data_cancel(struct cec_data *data, u8 tx_status) } else { list_del_init(&data->list); if (!(data->msg.tx_status & CEC_TX_STATUS_OK)) - data->adap->transmit_queue_sz--; + if (!WARN_ON(!data->adap->transmit_queue_sz)) + data->adap->transmit_queue_sz--; } if (data->msg.tx_status & CEC_TX_STATUS_OK) { @@ -430,6 +433,14 @@ static void cec_flush(struct cec_adapter *adap) * need to do anything special in that case. */ } + /* + * If something went wrong and this counter isn't what it should + * be, then this will reset it back to 0. Warn if it is not 0, + * since it indicates a bug, either in this framework or in a + * CEC driver. + */ + if (WARN_ON(adap->transmit_queue_sz)) + adap->transmit_queue_sz = 0; } /* @@ -454,7 +465,7 @@ int cec_thread_func(void *_adap) bool timeout = false; u8 attempts; - if (adap->transmitting) { + if (adap->transmit_in_progress) { int err; /* @@ -489,7 +500,7 @@ int cec_thread_func(void *_adap) goto unlock; } - if (adap->transmitting && timeout) { + if (adap->transmit_in_progress && timeout) { /* * If we timeout, then log that. Normally this does * not happen and it is an indication of a faulty CEC @@ -498,14 +509,18 @@ int cec_thread_func(void *_adap) * so much traffic on the bus that the adapter was * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). */ - pr_warn("cec-%s: message %*ph timed out\n", adap->name, - adap->transmitting->msg.len, - adap->transmitting->msg.msg); + if (adap->transmitting) { + pr_warn("cec-%s: message %*ph timed out\n", adap->name, + adap->transmitting->msg.len, + adap->transmitting->msg.msg); + /* Just give up on this. */ + cec_data_cancel(adap->transmitting, + CEC_TX_STATUS_TIMEOUT); + } else { + pr_warn("cec-%s: transmit timed out\n", adap->name); + } adap->transmit_in_progress = false; adap->tx_timeouts++; - /* Just give up on this. */ - cec_data_cancel(adap->transmitting, - CEC_TX_STATUS_TIMEOUT); goto unlock; } @@ -520,7 +535,8 @@ int cec_thread_func(void *_adap) data = list_first_entry(&adap->transmit_queue, struct cec_data, list); list_del_init(&data->list); - adap->transmit_queue_sz--; + if (!WARN_ON(!data->adap->transmit_queue_sz)) + adap->transmit_queue_sz--; /* Make this the current transmitting message */ adap->transmitting = data; @@ -1083,11 +1099,11 @@ void cec_received_msg_ts(struct cec_adapter *adap, valid_la = false; else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED)) valid_la = false; - else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4)) + else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST)) valid_la = false; else if (cec_msg_is_broadcast(msg) && - adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 && - !(dir_fl & BCAST2_0)) + adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0 && + !(dir_fl & BCAST1_4)) valid_la = false; } if (valid_la && min_len) { @@ -1976,7 +1992,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * Play function, this message can have variable length * depending on the specific play function that is used. */ - case 0x60: + case CEC_OP_UI_CMD_PLAY_FUNCTION: if (msg->len == 2) rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0); @@ -1993,8 +2009,12 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * For the time being these messages are not processed by the * framework and are simply forwarded to the user space. */ - case 0x56: case 0x57: - case 0x67: case 0x68: case 0x69: case 0x6a: + case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE: + case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION: + case CEC_OP_UI_CMD_TUNE_FUNCTION: + case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION: break; default: rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0); diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 12d676484472..17d1cb2e5f97 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -187,6 +187,21 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, return 0; } +static long cec_adap_g_connector_info(struct cec_adapter *adap, + struct cec_log_addrs __user *parg) +{ + int ret = 0; + + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) + return -ENOTTY; + + mutex_lock(&adap->lock); + if (copy_to_user(parg, &adap->conn_info, sizeof(adap->conn_info))) + ret = -EFAULT; + mutex_unlock(&adap->lock); + return ret; +} + static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, bool block, struct cec_msg __user *parg) { @@ -506,6 +521,9 @@ static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case CEC_ADAP_S_LOG_ADDRS: return cec_adap_s_log_addrs(adap, fh, block, parg); + case CEC_ADAP_G_CONNECTOR_INFO: + return cec_adap_g_connector_info(adap, parg); + case CEC_TRANSMIT: return cec_transmit(adap, fh, block, parg); @@ -578,6 +596,8 @@ static int cec_open(struct inode *inode, struct file *filp) /* Queue up initial state events */ ev.state_change.phys_addr = adap->phys_addr; ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + ev.state_change.have_conn_info = + adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR; cec_queue_event_fh(fh, &ev, 0); #ifdef CONFIG_CEC_PIN if (adap->pin && adap->pin->ops->read_hpd) { diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 9c610e1e99b8..db7adffcdc76 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -257,11 +257,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, struct cec_adapter *adap; int res; - /* - * Disable this capability until the connector info public API - * is ready. - */ - caps &= ~CEC_CAP_CONNECTOR_INFO; #ifndef CONFIG_MEDIA_CEC_RC caps &= ~CEC_CAP_RC; #endif diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 4d82a5522072..7cf42b133dbc 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -153,13 +153,14 @@ cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, } EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register); -void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +void cec_notifier_cec_adap_unregister(struct cec_notifier *n, + struct cec_adapter *adap) { if (!n) return; mutex_lock(&n->lock); - n->cec_adap->notifier = NULL; + adap->notifier = NULL; n->cec_adap = NULL; n->callback = NULL; mutex_unlock(&n->lock); diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index 8f987bc0dd88..660fe111f540 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -1279,6 +1279,15 @@ static void cec_pin_adap_free(struct cec_adapter *adap) kfree(pin); } +static int cec_pin_received(struct cec_adapter *adap, struct cec_msg *msg) +{ + struct cec_pin *pin = adap->pin; + + if (pin->ops->received) + return pin->ops->received(adap, msg); + return -ENOMSG; +} + void cec_pin_changed(struct cec_adapter *adap, bool value) { struct cec_pin *pin = adap->pin; @@ -1301,6 +1310,7 @@ static const struct cec_adap_ops cec_pin_adap_ops = { .error_inj_parse_line = cec_pin_error_inj_parse_line, .error_inj_show = cec_pin_error_inj_show, #endif + .received = cec_pin_received, }; struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, |