From 2c21ac0ae457310ec0044e4ff806e677af8253ab Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Dec 2017 03:56:52 -0500 Subject: media: cec-adap: add '0x' prefix when printing status It's not clear if the transmit status that is printed when debugging is enabled is hex or decimal. Add 0x prefix to make this explicit. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/cec') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 98f88c43f62c..91d72805ee59 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; -- cgit v1.2.3-59-g8ed1b From 48ea2e926b5ad29c0747fbd90e605cc56fb78298 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Nov 2017 07:36:36 -0500 Subject: media: cec: add the adap_monitor_pin_enable op Some devices can monitor the CEC pin using an interrupt, but you only want to enable the interrupt if you actually switch to pin monitoring mode. So add a new op that is called when pin monitoring needs to be switched on or off. Also fix a small bug where the initial CEC pin event was sent again when calling S_MODE twice with the same CEC_MODE_MONITOR_PIN mode. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 23 +++++++++++++++++++++++ drivers/media/cec/cec-api.c | 21 ++++++++++++++++----- drivers/media/cec/cec-priv.h | 2 ++ include/media/cec.h | 1 + 4 files changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers/media/cec') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 91d72805ee59..2a097e016414 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -2053,6 +2053,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 3dba3aa34a43..3eb4a069cde8 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -354,6 +354,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 +434,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 +454,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 +464,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) { @@ -608,7 +619,7 @@ 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); 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); diff --git a/include/media/cec.h b/include/media/cec.h index 16341210d3ba..dd781e928b72 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -122,6 +122,7 @@ struct cec_adap_ops { /* Low-level callbacks */ int (*adap_enable)(struct cec_adapter *adap, bool enable); int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); + int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable); int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg); -- cgit v1.2.3-59-g8ed1b From c8959a39fd47189a1474a4e92ffa34763589d6b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Nov 2017 04:12:39 -0500 Subject: media: cec: disable the hardware when unregistered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the device is being unregistered disable the hardware, don't wait until cec_delete_adapter is called as the hardware may have disappeared by then. This would be the case for hotplugable devices. Signed-off-by: Hans Verkuil Reported-by: Bård Eirik Winther Tested-by: Bård Eirik Winther Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-api.c | 11 ++++------- drivers/media/cec/cec-core.c | 15 +++++++++------ include/media/cec.h | 12 ++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers/media/cec') diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 3eb4a069cde8..37e468074dc1 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 unsigned int 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; unsigned int res = 0; - if (!devnode->registered) + if (!cec_is_registered(adap)) return POLLERR | POLLHUP; mutex_lock(&adap->lock); if (adap->is_configured && @@ -486,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) { @@ -626,9 +624,8 @@ static int cec_release(struct inode *inode, struct file *filp) 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..b5845b47fe6c 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; @@ -373,7 +379,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 +387,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/include/media/cec.h b/include/media/cec.h index dd781e928b72..1c6a797cb6d4 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -230,6 +230,18 @@ static inline bool cec_is_sink(const struct cec_adapter *adap) return adap->phys_addr == 0; } +/** + * cec_is_registered() - is the CEC adapter registered? + * + * @adap: the CEC adapter, may be NULL. + * + * Return: true if the adapter is registered, false otherwise. + */ +static inline bool cec_is_registered(const struct cec_adapter *adap) +{ + return adap && adap->devnode.registered; +} + #define cec_phys_addr_exp(pa) \ ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf -- cgit v1.2.3-59-g8ed1b From 57c642cb45d6f7d0d950c3bc67439989062ac743 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 23 Nov 2017 17:37:10 -0500 Subject: media: cec: move cec autorepeat handling to rc-core CEC autorepeat is different than other protocols. Autorepeat is triggered by the first repeated user control pressed CEC message, rather than a fixed REP_DELAY. This change also does away with the KEY_UP event directly after the first KEY_DOWN event, which was used to stop autorepeat from starting. See commit a9a249a2c997 ("media: cec: fix remote control passthrough") for the original change. Acked-by: Hans Verkuil Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 56 ++++---------------------------------------- drivers/media/cec/cec-core.c | 12 ---------- drivers/media/rc/rc-main.c | 49 +++++++++++++++++++++++++++++++++++++- include/media/cec.h | 5 ---- include/media/rc-core.h | 3 +++ 5 files changed, 56 insertions(+), 69 deletions(-) (limited to 'drivers/media/cec') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 2a097e016414..2b1e540587d6 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -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; diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index b5845b47fe6c..a9f9525db9ae 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -286,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; } @@ -318,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 diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5830cb2c5943..1870b7999062 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -597,6 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync) return; IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); + del_timer_sync(&dev->timer_repeat); input_report_key(dev->input_dev, dev->last_keycode, 0); led_trigger_event(led_feedback, LED_OFF); if (sync) @@ -650,6 +651,31 @@ static void ir_timer_keyup(struct timer_list *t) spin_unlock_irqrestore(&dev->keylock, flags); } +/** + * ir_timer_repeat() - generates a repeat event after a timeout + * + * @t: a pointer to the struct timer_list + * + * This routine will generate a soft repeat event every REP_PERIOD + * milliseconds. + */ +static void ir_timer_repeat(struct timer_list *t) +{ + struct rc_dev *dev = from_timer(dev, t, timer_repeat); + struct input_dev *input = dev->input_dev; + unsigned long flags; + + spin_lock_irqsave(&dev->keylock, flags); + if (dev->keypressed) { + input_event(input, EV_KEY, dev->last_keycode, 2); + input_sync(input); + if (input->rep[REP_PERIOD]) + mod_timer(&dev->timer_repeat, jiffies + + msecs_to_jiffies(input->rep[REP_PERIOD])); + } + spin_unlock_irqrestore(&dev->keylock, flags); +} + /** * rc_repeat() - signals that a key is still pressed * @dev: the struct rc_dev descriptor of the device @@ -732,6 +758,22 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, led_trigger_event(led_feedback, LED_FULL); } + /* + * For CEC, start sending repeat messages as soon as the first + * repeated message is sent, as long as REP_DELAY = 0 and REP_PERIOD + * is non-zero. Otherwise, the input layer will generate repeat + * messages. + */ + if (!new_event && keycode != KEY_RESERVED && + dev->allowed_protocols == RC_PROTO_BIT_CEC && + !timer_pending(&dev->timer_repeat) && + dev->input_dev->rep[REP_PERIOD] && + !dev->input_dev->rep[REP_DELAY]) { + input_event(dev->input_dev, EV_KEY, keycode, 2); + mod_timer(&dev->timer_repeat, jiffies + + msecs_to_jiffies(dev->input_dev->rep[REP_PERIOD])); + } + input_sync(dev->input_dev); } @@ -1599,6 +1641,7 @@ struct rc_dev *rc_allocate_device(enum rc_driver_type type) input_set_drvdata(dev->input_dev, dev); timer_setup(&dev->timer_keyup, ir_timer_keyup, 0); + timer_setup(&dev->timer_repeat, ir_timer_repeat, 0); spin_lock_init(&dev->rc_map.lock); spin_lock_init(&dev->keylock); @@ -1732,7 +1775,10 @@ static int rc_setup_rx_device(struct rc_dev *dev) * to avoid wrong repetition of the keycodes. Note that this must be * set after the call to input_register_device(). */ - dev->input_dev->rep[REP_DELAY] = 500; + if (dev->allowed_protocols == RC_PROTO_BIT_CEC) + dev->input_dev->rep[REP_DELAY] = 0; + else + dev->input_dev->rep[REP_DELAY] = 500; /* * As a repeat event on protocols like RC-5 and NEC take as long as @@ -1884,6 +1930,7 @@ void rc_unregister_device(struct rc_dev *dev) return; del_timer_sync(&dev->timer_keyup); + del_timer_sync(&dev->timer_repeat); if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); diff --git a/include/media/cec.h b/include/media/cec.h index 1c6a797cb6d4..7cdf71d7125a 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -192,11 +192,6 @@ struct cec_adapter { u32 tx_timeouts; -#ifdef CONFIG_MEDIA_CEC_RC - bool rc_repeating; - int rc_last_scancode; - u64 rc_last_keypress; -#endif #ifdef CONFIG_CEC_NOTIFIER struct cec_notifier *notifier; #endif diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 3a47a25a6593..0a4026cf64f3 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -134,6 +134,8 @@ struct lirc_fh { * @keypressed: whether a key is currently pressed * @keyup_jiffies: time (in jiffies) when the current keypress should be released * @timer_keyup: timer for releasing a keypress + * @timer_repeat: timer for autorepeat events. This is needed for CEC, which + * has non-standard repeats. * @last_keycode: keycode of last keypress * @last_protocol: protocol of last keypress * @last_scancode: scancode of last keypress @@ -202,6 +204,7 @@ struct rc_dev { bool keypressed; unsigned long keyup_jiffies; struct timer_list timer_keyup; + struct timer_list timer_repeat; u32 last_keycode; enum rc_proto last_protocol; u32 last_scancode; -- cgit v1.2.3-59-g8ed1b