Merge tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - Documentation for digital TV (both kAPI and uAPI) are now in sync with the implementation (except for legacy/deprecated ioctls). This is a major step, as there were always a gap there - New sensor driver: imx274 - New cec driver: cec-gpio - New platform driver for rockship rga and tegra CEC - New RC driver: tango-ir - Several cleanups at atomisp driver - Core improvements for RC, CEC, V4L2 async probing support and DVB - Lots of drivers cleanup, fixes and improvements. * tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (332 commits) dvb_frontend: don't use-after-free the frontend struct media: dib0700: fix invalid dvb_detach argument media: v4l2-ctrls: Don't validate BITMASK twice media: s5p-mfc: fix lockdep warning media: dvb-core: always call invoke_release() in fe_free() media: usb: dvb-usb-v2: dvb_usb_core: remove redundant code in dvb_usb_fe_sleep media: au0828: make const array addr_list static media: cx88: make const arrays default_addr_list and pvr2000_addr_list static media: drxd: make const array fastIncrDecLUT static media: usb: fix spelling mistake: "synchronuously" -> "synchronously" media: ddbridge: fix build warnings media: av7110: avoid 2038 overflow in debug print media: Don't do DMA on stack for firmware upload in the AS102 driver media: v4l: async: fix unregister for implicitly registered sub-device notifiers media: v4l: async: fix return of unitialized variable ret media: imx274: fix missing return assignment from call to imx274_mode_regs media: camss-vfe: always initialize reg at vfe_set_xbar_cfg() media: atomisp: make function calls cleaner media: atomisp: get rid of storage_class.h media: atomisp: get rid of wrong stddef.h include ...
This commit is contained in:
@@ -86,7 +86,7 @@ void cec_queue_event_fh(struct cec_fh *fh,
|
||||
const struct cec_event *new_ev, u64 ts)
|
||||
{
|
||||
static const u8 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 64, 64,
|
||||
1, 1, 64, 64, 8, 8,
|
||||
};
|
||||
struct cec_event_entry *entry;
|
||||
unsigned int ev_idx = new_ev->event - 1;
|
||||
@@ -170,6 +170,22 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event);
|
||||
|
||||
/* Notify userspace that the HPD pin changed state at the given time. */
|
||||
void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
{
|
||||
struct cec_event ev = {
|
||||
.event = is_high ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW,
|
||||
};
|
||||
struct cec_fh *fh;
|
||||
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list)
|
||||
cec_queue_event_fh(fh, &ev, ktime_to_ns(ts));
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event);
|
||||
|
||||
/*
|
||||
* Queue a new message for this filehandle.
|
||||
*
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <media/cec-pin.h>
|
||||
#include "cec-priv.h"
|
||||
#include "cec-pin-priv.h"
|
||||
|
||||
static inline struct cec_devnode *cec_devnode_data(struct file *filp)
|
||||
{
|
||||
@@ -529,7 +530,7 @@ static int cec_open(struct inode *inode, struct file *filp)
|
||||
* Initial events that are automatically sent when the cec device is
|
||||
* opened.
|
||||
*/
|
||||
struct cec_event ev_state = {
|
||||
struct cec_event ev = {
|
||||
.event = CEC_EVENT_STATE_CHANGE,
|
||||
.flags = CEC_EVENT_FL_INITIAL_STATE,
|
||||
};
|
||||
@@ -569,9 +570,19 @@ static int cec_open(struct inode *inode, struct file *filp)
|
||||
filp->private_data = fh;
|
||||
|
||||
/* Queue up initial state events */
|
||||
ev_state.state_change.phys_addr = adap->phys_addr;
|
||||
ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev_state, 0);
|
||||
ev.state_change.phys_addr = adap->phys_addr;
|
||||
ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
#ifdef CONFIG_CEC_PIN
|
||||
if (adap->pin && adap->pin->ops->read_hpd) {
|
||||
err = adap->pin->ops->read_hpd(adap);
|
||||
if (err >= 0) {
|
||||
ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
list_add(&fh->list, &devnode->fhs);
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
||||
@@ -112,10 +112,6 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
||||
int minor;
|
||||
int ret;
|
||||
|
||||
/* Initialization */
|
||||
INIT_LIST_HEAD(&devnode->fhs);
|
||||
mutex_init(&devnode->lock);
|
||||
|
||||
/* Part 1: Find a free minor number */
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0);
|
||||
@@ -242,6 +238,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
INIT_LIST_HEAD(&adap->wait_queue);
|
||||
init_waitqueue_head(&adap->kthread_waitq);
|
||||
|
||||
/* adap->devnode initialization */
|
||||
INIT_LIST_HEAD(&adap->devnode.fhs);
|
||||
mutex_init(&adap->devnode.lock);
|
||||
|
||||
adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name);
|
||||
if (IS_ERR(adap->kthread)) {
|
||||
pr_err("cec-%s: kernel_thread() failed\n", name);
|
||||
@@ -277,7 +277,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
adap->rc->input_id.version = 1;
|
||||
adap->rc->driver_name = CEC_NAME;
|
||||
adap->rc->allowed_protocols = RC_PROTO_BIT_CEC;
|
||||
adap->rc->enabled_protocols = RC_PROTO_BIT_CEC;
|
||||
adap->rc->priv = adap;
|
||||
adap->rc->map_name = RC_MAP_CEC;
|
||||
adap->rc->timeout = MS_TO_NS(100);
|
||||
|
||||
133
drivers/media/cec/cec-pin-priv.h
Normal file
133
drivers/media/cec/cec-pin-priv.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* cec-pin-priv.h - internal cec-pin header
|
||||
*
|
||||
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_CEC_PIN_PRIV_H
|
||||
#define LINUX_CEC_PIN_PRIV_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <media/cec-pin.h>
|
||||
|
||||
enum cec_pin_state {
|
||||
/* CEC is off */
|
||||
CEC_ST_OFF,
|
||||
/* CEC is idle, waiting for Rx or Tx */
|
||||
CEC_ST_IDLE,
|
||||
|
||||
/* Tx states */
|
||||
|
||||
/* Pending Tx, waiting for Signal Free Time to expire */
|
||||
CEC_ST_TX_WAIT,
|
||||
/* Low-drive was detected, wait for bus to go high */
|
||||
CEC_ST_TX_WAIT_FOR_HIGH,
|
||||
/* Drive CEC low for the start bit */
|
||||
CEC_ST_TX_START_BIT_LOW,
|
||||
/* Drive CEC high for the start bit */
|
||||
CEC_ST_TX_START_BIT_HIGH,
|
||||
/* Drive CEC low for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_LOW,
|
||||
/* Drive CEC high for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_HIGH,
|
||||
/* Drive CEC low for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_LOW,
|
||||
/* Drive CEC high for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH,
|
||||
/*
|
||||
* Wait for start of sample time to check for Ack bit or first
|
||||
* four initiator bits to check for Arbitration Lost.
|
||||
*/
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE,
|
||||
/* Wait for end of bit period after sampling */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE,
|
||||
|
||||
/* Rx states */
|
||||
|
||||
/* Start bit low detected */
|
||||
CEC_ST_RX_START_BIT_LOW,
|
||||
/* Start bit high detected */
|
||||
CEC_ST_RX_START_BIT_HIGH,
|
||||
/* Wait for bit sample time */
|
||||
CEC_ST_RX_DATA_SAMPLE,
|
||||
/* Wait for earliest end of bit period after sampling */
|
||||
CEC_ST_RX_DATA_POST_SAMPLE,
|
||||
/* Wait for CEC to go high (i.e. end of bit period */
|
||||
CEC_ST_RX_DATA_HIGH,
|
||||
/* Drive CEC low to send 0 Ack bit */
|
||||
CEC_ST_RX_ACK_LOW,
|
||||
/* End of 0 Ack time, wait for earliest end of bit period */
|
||||
CEC_ST_RX_ACK_LOW_POST,
|
||||
/* Wait for CEC to go high (i.e. end of bit period */
|
||||
CEC_ST_RX_ACK_HIGH_POST,
|
||||
/* Wait for earliest end of bit period and end of message */
|
||||
CEC_ST_RX_ACK_FINISH,
|
||||
|
||||
/* Start low drive */
|
||||
CEC_ST_LOW_DRIVE,
|
||||
/* Monitor pin using interrupts */
|
||||
CEC_ST_RX_IRQ,
|
||||
|
||||
/* Total number of pin states */
|
||||
CEC_PIN_STATES
|
||||
};
|
||||
|
||||
#define CEC_NUM_PIN_EVENTS 128
|
||||
|
||||
#define CEC_PIN_IRQ_UNCHANGED 0
|
||||
#define CEC_PIN_IRQ_DISABLE 1
|
||||
#define CEC_PIN_IRQ_ENABLE 2
|
||||
|
||||
struct cec_pin {
|
||||
struct cec_adapter *adap;
|
||||
const struct cec_pin_ops *ops;
|
||||
struct task_struct *kthread;
|
||||
wait_queue_head_t kthread_waitq;
|
||||
struct hrtimer timer;
|
||||
ktime_t ts;
|
||||
unsigned int wait_usecs;
|
||||
u16 la_mask;
|
||||
bool enabled;
|
||||
bool monitor_all;
|
||||
bool rx_eom;
|
||||
bool enable_irq_failed;
|
||||
enum cec_pin_state state;
|
||||
struct cec_msg tx_msg;
|
||||
u32 tx_bit;
|
||||
bool tx_nacked;
|
||||
u32 tx_signal_free_time;
|
||||
struct cec_msg rx_msg;
|
||||
u32 rx_bit;
|
||||
|
||||
struct cec_msg work_rx_msg;
|
||||
u8 work_tx_status;
|
||||
ktime_t work_tx_ts;
|
||||
atomic_t work_irq_change;
|
||||
atomic_t work_pin_events;
|
||||
unsigned int work_pin_events_wr;
|
||||
unsigned int work_pin_events_rd;
|
||||
ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS];
|
||||
bool work_pin_is_high[CEC_NUM_PIN_EVENTS];
|
||||
ktime_t timer_ts;
|
||||
u32 timer_cnt;
|
||||
u32 timer_100ms_overruns;
|
||||
u32 timer_300ms_overruns;
|
||||
u32 timer_max_overrun;
|
||||
u32 timer_sum_overrun;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/sched/types.h>
|
||||
|
||||
#include <media/cec-pin.h>
|
||||
#include "cec-pin-priv.h"
|
||||
|
||||
/* All timings are in microseconds */
|
||||
|
||||
@@ -132,7 +133,7 @@ static void cec_pin_to_idle(struct cec_pin *pin)
|
||||
pin->rx_msg.len = 0;
|
||||
memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg));
|
||||
pin->state = CEC_ST_IDLE;
|
||||
pin->ts = 0;
|
||||
pin->ts = ns_to_ktime(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -426,7 +427,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
|
||||
v = cec_pin_read(pin);
|
||||
if (v && pin->rx_eom) {
|
||||
pin->work_rx_msg = pin->rx_msg;
|
||||
pin->work_rx_msg.rx_ts = ts;
|
||||
pin->work_rx_msg.rx_ts = ktime_to_ns(ts);
|
||||
wake_up_interruptible(&pin->kthread_waitq);
|
||||
pin->ts = ts;
|
||||
pin->state = CEC_ST_RX_ACK_FINISH;
|
||||
@@ -457,7 +458,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
||||
s32 delta;
|
||||
|
||||
ts = ktime_get();
|
||||
if (pin->timer_ts) {
|
||||
if (ktime_to_ns(pin->timer_ts)) {
|
||||
delta = ktime_us_delta(ts, pin->timer_ts);
|
||||
pin->timer_cnt++;
|
||||
if (delta > 100 && pin->state != CEC_ST_IDLE) {
|
||||
@@ -481,17 +482,19 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
||||
if (pin->wait_usecs > 150) {
|
||||
pin->wait_usecs -= 100;
|
||||
pin->timer_ts = ktime_add_us(ts, 100);
|
||||
hrtimer_forward_now(timer, 100000);
|
||||
hrtimer_forward_now(timer, ns_to_ktime(100000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
if (pin->wait_usecs > 100) {
|
||||
pin->wait_usecs /= 2;
|
||||
pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
|
||||
hrtimer_forward_now(timer, pin->wait_usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(pin->wait_usecs * 1000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
|
||||
hrtimer_forward_now(timer, pin->wait_usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(pin->wait_usecs * 1000));
|
||||
pin->wait_usecs = 0;
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
@@ -531,7 +534,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
||||
pin->state = CEC_ST_RX_START_BIT_LOW;
|
||||
break;
|
||||
}
|
||||
if (pin->ts == 0)
|
||||
if (ktime_to_ns(pin->ts) == 0)
|
||||
pin->ts = ts;
|
||||
if (pin->tx_msg.len) {
|
||||
/*
|
||||
@@ -572,12 +575,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
||||
if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) {
|
||||
pin->wait_usecs = 0;
|
||||
pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs);
|
||||
hrtimer_forward_now(timer, states[pin->state].usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(states[pin->state].usecs * 1000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
pin->wait_usecs = states[pin->state].usecs - 100;
|
||||
pin->timer_ts = ktime_add_us(ts, 100);
|
||||
hrtimer_forward_now(timer, 100000);
|
||||
hrtimer_forward_now(timer, ns_to_ktime(100000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
@@ -596,7 +600,7 @@ static int cec_pin_thread_func(void *_adap)
|
||||
|
||||
if (pin->work_rx_msg.len) {
|
||||
cec_received_msg_ts(adap, &pin->work_rx_msg,
|
||||
pin->work_rx_msg.rx_ts);
|
||||
ns_to_ktime(pin->work_rx_msg.rx_ts));
|
||||
pin->work_rx_msg.len = 0;
|
||||
}
|
||||
if (pin->work_tx_status) {
|
||||
@@ -623,13 +627,15 @@ static int cec_pin_thread_func(void *_adap)
|
||||
pin->ops->disable_irq(adap);
|
||||
cec_pin_high(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
break;
|
||||
case CEC_PIN_IRQ_ENABLE:
|
||||
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
|
||||
if (pin->enable_irq_failed) {
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -653,7 +659,7 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
cec_pin_read(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
pin->tx_msg.len = 0;
|
||||
pin->timer_ts = 0;
|
||||
pin->timer_ts = ns_to_ktime(0);
|
||||
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
|
||||
pin->kthread = kthread_run(cec_pin_thread_func, adap,
|
||||
"cec-pin");
|
||||
@@ -661,7 +667,8 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
pr_err("cec-pin: kernel_thread() failed\n");
|
||||
return PTR_ERR(pin->kthread);
|
||||
}
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
} else {
|
||||
if (pin->ops->disable_irq)
|
||||
pin->ops->disable_irq(adap);
|
||||
@@ -699,7 +706,8 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
pin->ops->disable_irq(adap);
|
||||
cec_pin_high(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -789,7 +797,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
|
||||
caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN,
|
||||
CEC_MAX_LOG_ADDRS);
|
||||
|
||||
if (PTR_ERR_OR_ZERO(adap)) {
|
||||
if (IS_ERR(adap)) {
|
||||
kfree(pin);
|
||||
return adap;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user