diff options
Diffstat (limited to 'drivers/media/cec')
-rw-r--r-- | drivers/media/cec/cec-adap.c | 81 | ||||
-rw-r--r-- | drivers/media/cec/cec-api.c | 32 | ||||
-rw-r--r-- | drivers/media/cec/cec-core.c | 27 | ||||
-rw-r--r-- | drivers/media/cec/cec-priv.h | 2 |
4 files changed, 60 insertions, 82 deletions
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 98f88c43f62c..2b1e540587d6 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -540,7 +540,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, unsigned int attempts_made = arb_lost_cnt + nack_cnt + low_drive_cnt + error_cnt; - dprintk(2, "%s: status %02x\n", __func__, status); + dprintk(2, "%s: status 0x%02x\n", __func__, status); if (attempts_made < 1) attempts_made = 1; @@ -1788,9 +1788,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, int la_idx = cec_log_addr2idx(adap, dest_laddr); bool from_unregistered = init_laddr == 0xf; struct cec_msg tx_cec_msg = { }; -#ifdef CONFIG_MEDIA_CEC_RC - int scancode; -#endif dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); @@ -1886,9 +1883,11 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, */ case 0x60: if (msg->len == 2) - scancode = msg->msg[2]; + rc_keydown(adap->rc, RC_PROTO_CEC, + msg->msg[2], 0); else - scancode = msg->msg[2] << 8 | msg->msg[3]; + rc_keydown(adap->rc, RC_PROTO_CEC, + msg->msg[2] << 8 | msg->msg[3], 0); break; /* * Other function messages that are not handled. @@ -1901,54 +1900,11 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, */ case 0x56: case 0x57: case 0x67: case 0x68: case 0x69: case 0x6a: - scancode = -1; break; default: - scancode = msg->msg[2]; - break; - } - - /* Was repeating, but keypress timed out */ - if (adap->rc_repeating && !adap->rc->keypressed) { - adap->rc_repeating = false; - adap->rc_last_scancode = -1; - } - /* Different keypress from last time, ends repeat mode */ - if (adap->rc_last_scancode != scancode) { - rc_keyup(adap->rc); - adap->rc_repeating = false; - } - /* We can't handle this scancode */ - if (scancode < 0) { - adap->rc_last_scancode = scancode; - break; - } - - /* Send key press */ - rc_keydown(adap->rc, RC_PROTO_CEC, scancode, 0); - - /* When in repeating mode, we're done */ - if (adap->rc_repeating) - break; - - /* - * We are not repeating, but the new scancode is - * the same as the last one, and this second key press is - * within 550 ms (the 'Follower Safety Timeout') from the - * previous key press, so we now enable the repeating mode. - */ - if (adap->rc_last_scancode == scancode && - msg->rx_ts - adap->rc_last_keypress < 550 * NSEC_PER_MSEC) { - adap->rc_repeating = true; + rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0); break; } - /* - * Not in repeating mode, so avoid triggering repeat mode - * by calling keyup. - */ - rc_keyup(adap->rc); - adap->rc_last_scancode = scancode; - adap->rc_last_keypress = msg->rx_ts; #endif break; @@ -1958,8 +1914,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, break; #ifdef CONFIG_MEDIA_CEC_RC rc_keyup(adap->rc); - adap->rc_repeating = false; - adap->rc_last_scancode = -1; #endif break; @@ -2053,6 +2007,29 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap) WARN_ON(call_op(adap, adap_monitor_all_enable, 0)); } +/* + * Helper functions to keep track of the 'monitor pin' use count. + * + * These functions are called with adap->lock held. + */ +int cec_monitor_pin_cnt_inc(struct cec_adapter *adap) +{ + int ret = 0; + + if (adap->monitor_pin_cnt == 0) + ret = call_op(adap, adap_monitor_pin_enable, 1); + if (ret == 0) + adap->monitor_pin_cnt++; + return ret; +} + +void cec_monitor_pin_cnt_dec(struct cec_adapter *adap) +{ + adap->monitor_pin_cnt--; + if (adap->monitor_pin_cnt == 0) + WARN_ON(call_op(adap, adap_monitor_pin_enable, 0)); +} + #ifdef CONFIG_DEBUG_FS /* * Log the current state of the CEC adapter. diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 9d6c496f756c..ecc89d9a279b 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -46,12 +46,11 @@ static inline struct cec_devnode *cec_devnode_data(struct file *filp) static __poll_t cec_poll(struct file *filp, struct poll_table_struct *poll) { - struct cec_devnode *devnode = cec_devnode_data(filp); struct cec_fh *fh = filp->private_data; struct cec_adapter *adap = fh->adap; __poll_t res = 0; - if (!devnode->registered) + if (!cec_is_registered(adap)) return POLLERR | POLLHUP; mutex_lock(&adap->lock); if (adap->is_configured && @@ -354,6 +353,7 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, u32 mode; u8 mode_initiator; u8 mode_follower; + bool send_pin_event = false; long err = 0; if (copy_from_user(&mode, parg, sizeof(mode))) @@ -433,6 +433,19 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, } } + if (!err) { + bool old_mon_pin = fh->mode_follower == CEC_MODE_MONITOR_PIN; + bool new_mon_pin = mode_follower == CEC_MODE_MONITOR_PIN; + + if (old_mon_pin != new_mon_pin) { + send_pin_event = new_mon_pin; + if (new_mon_pin) + err = cec_monitor_pin_cnt_inc(adap); + else + cec_monitor_pin_cnt_dec(adap); + } + } + if (err) { mutex_unlock(&adap->lock); return err; @@ -440,11 +453,9 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, if (fh->mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt--; - if (fh->mode_follower == CEC_MODE_MONITOR_PIN) - adap->monitor_pin_cnt--; if (mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt++; - if (mode_follower == CEC_MODE_MONITOR_PIN) { + if (send_pin_event) { struct cec_event ev = { .flags = CEC_EVENT_FL_INITIAL_STATE, }; @@ -452,7 +463,6 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, ev.event = adap->cec_pin_is_high ? CEC_EVENT_PIN_CEC_HIGH : CEC_EVENT_PIN_CEC_LOW; cec_queue_event_fh(fh, &ev, 0); - adap->monitor_pin_cnt++; } if (mode_follower == CEC_MODE_EXCL_FOLLOWER || mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { @@ -475,13 +485,12 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct cec_devnode *devnode = cec_devnode_data(filp); struct cec_fh *fh = filp->private_data; struct cec_adapter *adap = fh->adap; bool block = !(filp->f_flags & O_NONBLOCK); void __user *parg = (void __user *)arg; - if (!devnode->registered) + if (!cec_is_registered(adap)) return -ENODEV; switch (cmd) { @@ -608,16 +617,15 @@ static int cec_release(struct inode *inode, struct file *filp) if (fh->mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt--; if (fh->mode_follower == CEC_MODE_MONITOR_PIN) - adap->monitor_pin_cnt--; + cec_monitor_pin_cnt_dec(adap); if (fh->mode_follower == CEC_MODE_MONITOR_ALL) cec_monitor_all_cnt_dec(adap); mutex_unlock(&adap->lock); mutex_lock(&devnode->lock); list_del(&fh->list); - if (list_empty(&devnode->fhs) && - !adap->needs_hpd && - adap->phys_addr == CEC_PHYS_ADDR_INVALID) { + if (cec_is_registered(adap) && list_empty(&devnode->fhs) && + !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) { WARN_ON(adap->ops->adap_enable(adap, false)); } mutex_unlock(&devnode->lock); diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 5870da6a567f..a9f9525db9ae 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -160,8 +160,9 @@ clr_bit: * This function can safely be called if the device node has never been * registered or has already been unregistered. */ -static void cec_devnode_unregister(struct cec_devnode *devnode) +static void cec_devnode_unregister(struct cec_adapter *adap) { + struct cec_devnode *devnode = &adap->devnode; struct cec_fh *fh; mutex_lock(&devnode->lock); @@ -179,6 +180,11 @@ static void cec_devnode_unregister(struct cec_devnode *devnode) devnode->unregistered = true; mutex_unlock(&devnode->lock); + mutex_lock(&adap->lock); + __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); + __cec_s_log_addrs(adap, NULL, false); + mutex_unlock(&adap->lock); + cdev_device_del(&devnode->cdev, &devnode->dev); put_device(&devnode->dev); } @@ -192,7 +198,7 @@ static void cec_cec_notify(struct cec_adapter *adap, u16 pa) void cec_register_cec_notifier(struct cec_adapter *adap, struct cec_notifier *notifier) { - if (WARN_ON(!adap->devnode.registered)) + if (WARN_ON(!cec_is_registered(adap))) return; adap->notifier = notifier; @@ -280,7 +286,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->priv = adap; adap->rc->map_name = RC_MAP_CEC; adap->rc->timeout = MS_TO_NS(100); - adap->rc_last_scancode = -1; #endif return adap; } @@ -312,17 +317,6 @@ int cec_register_adapter(struct cec_adapter *adap, adap->rc = NULL; return res; } - /* - * The REP_DELAY for CEC is really the time between the initial - * 'User Control Pressed' message and the second. The first - * keypress is always seen as non-repeating, the second - * (provided it has the same UI Command) will start the 'Press - * and Hold' (aka repeat) behavior. By setting REP_DELAY to the - * same value as REP_PERIOD the expected CEC behavior is - * reproduced. - */ - adap->rc->input_dev->rep[REP_DELAY] = - adap->rc->input_dev->rep[REP_PERIOD]; } #endif @@ -373,7 +367,7 @@ void cec_unregister_adapter(struct cec_adapter *adap) if (adap->notifier) cec_notifier_unregister(adap->notifier); #endif - cec_devnode_unregister(&adap->devnode); + cec_devnode_unregister(adap); } EXPORT_SYMBOL_GPL(cec_unregister_adapter); @@ -381,9 +375,6 @@ void cec_delete_adapter(struct cec_adapter *adap) { if (IS_ERR_OR_NULL(adap)) return; - mutex_lock(&adap->lock); - __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); - mutex_unlock(&adap->lock); kthread_stop(adap->kthread); if (adap->kthread_config) kthread_stop(adap->kthread_config); diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index 70767a7900f2..daf597643af8 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -40,6 +40,8 @@ void cec_put_device(struct cec_devnode *devnode); /* cec-adap.c */ int cec_monitor_all_cnt_inc(struct cec_adapter *adap); void cec_monitor_all_cnt_dec(struct cec_adapter *adap); +int cec_monitor_pin_cnt_inc(struct cec_adapter *adap); +void cec_monitor_pin_cnt_dec(struct cec_adapter *adap); int cec_adap_status(struct seq_file *file, void *priv); int cec_thread_func(void *_adap); void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); |