linux/drivers/media/platform/vivid/vivid-cec.c
<<
>>
Prefs
   1/*
   2 * vivid-cec.c - A Virtual Video Test Driver, cec emulation
   3 *
   4 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
   5 *
   6 * This program is free software; you may redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; version 2 of the License.
   9 *
  10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17 * SOFTWARE.
  18 */
  19
  20#include <media/cec.h>
  21
  22#include "vivid-core.h"
  23#include "vivid-cec.h"
  24
  25#define CEC_TIM_START_BIT_TOTAL         4500
  26#define CEC_TIM_START_BIT_LOW           3700
  27#define CEC_TIM_START_BIT_HIGH          800
  28#define CEC_TIM_DATA_BIT_TOTAL          2400
  29#define CEC_TIM_DATA_BIT_0_LOW          1500
  30#define CEC_TIM_DATA_BIT_0_HIGH         900
  31#define CEC_TIM_DATA_BIT_1_LOW          600
  32#define CEC_TIM_DATA_BIT_1_HIGH         1800
  33
  34void vivid_cec_bus_free_work(struct vivid_dev *dev)
  35{
  36        spin_lock(&dev->cec_slock);
  37        while (!list_empty(&dev->cec_work_list)) {
  38                struct vivid_cec_work *cw =
  39                        list_first_entry(&dev->cec_work_list,
  40                                         struct vivid_cec_work, list);
  41
  42                spin_unlock(&dev->cec_slock);
  43                cancel_delayed_work_sync(&cw->work);
  44                spin_lock(&dev->cec_slock);
  45                list_del(&cw->list);
  46                cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE);
  47                kfree(cw);
  48        }
  49        spin_unlock(&dev->cec_slock);
  50}
  51
  52static bool vivid_cec_find_dest_adap(struct vivid_dev *dev,
  53                                     struct cec_adapter *adap, u8 dest)
  54{
  55        unsigned int i;
  56
  57        if (dest >= 0xf)
  58                return false;
  59
  60        if (adap != dev->cec_rx_adap && dev->cec_rx_adap &&
  61            dev->cec_rx_adap->is_configured &&
  62            cec_has_log_addr(dev->cec_rx_adap, dest))
  63                return true;
  64
  65        for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
  66                if (adap == dev->cec_tx_adap[i])
  67                        continue;
  68                if (!dev->cec_tx_adap[i]->is_configured)
  69                        continue;
  70                if (cec_has_log_addr(dev->cec_tx_adap[i], dest))
  71                        return true;
  72        }
  73        return false;
  74}
  75
  76static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts,
  77                                      const struct cec_msg *msg, bool nacked)
  78{
  79        unsigned int len = nacked ? 1 : msg->len;
  80        unsigned int i;
  81        bool bit;
  82
  83        if (adap == NULL)
  84                return;
  85        ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL +
  86                               len * 10 * CEC_TIM_DATA_BIT_TOTAL));
  87        cec_queue_pin_cec_event(adap, false, ts);
  88        ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW);
  89        cec_queue_pin_cec_event(adap, true, ts);
  90        ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH);
  91
  92        for (i = 0; i < 10 * len; i++) {
  93                switch (i % 10) {
  94                case 0 ... 7:
  95                        bit = msg->msg[i / 10] & (0x80 >> (i % 10));
  96                        break;
  97                case 8: /* EOM */
  98                        bit = i / 10 == msg->len - 1;
  99                        break;
 100                case 9: /* ACK */
 101                        bit = cec_msg_is_broadcast(msg) ^ nacked;
 102                        break;
 103                }
 104                cec_queue_pin_cec_event(adap, false, ts);
 105                if (bit)
 106                        ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW);
 107                else
 108                        ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW);
 109                cec_queue_pin_cec_event(adap, true, ts);
 110                if (bit)
 111                        ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH);
 112                else
 113                        ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH);
 114        }
 115}
 116
 117static void vivid_cec_pin_events(struct vivid_dev *dev,
 118                                 const struct cec_msg *msg, bool nacked)
 119{
 120        ktime_t ts = ktime_get();
 121        unsigned int i;
 122
 123        vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked);
 124        for (i = 0; i < MAX_OUTPUTS; i++)
 125                vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked);
 126}
 127
 128static void vivid_cec_xfer_done_worker(struct work_struct *work)
 129{
 130        struct vivid_cec_work *cw =
 131                container_of(work, struct vivid_cec_work, work.work);
 132        struct vivid_dev *dev = cw->dev;
 133        struct cec_adapter *adap = cw->adap;
 134        u8 dest = cec_msg_destination(&cw->msg);
 135        bool valid_dest;
 136        unsigned int i;
 137
 138        valid_dest = cec_msg_is_broadcast(&cw->msg);
 139        if (!valid_dest)
 140                valid_dest = vivid_cec_find_dest_adap(dev, adap, dest);
 141
 142        cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK;
 143        spin_lock(&dev->cec_slock);
 144        dev->cec_xfer_time_jiffies = 0;
 145        dev->cec_xfer_start_jiffies = 0;
 146        list_del(&cw->list);
 147        spin_unlock(&dev->cec_slock);
 148        vivid_cec_pin_events(dev, &cw->msg, !valid_dest);
 149        cec_transmit_attempt_done(cw->adap, cw->tx_status);
 150
 151        /* Broadcast message */
 152        if (adap != dev->cec_rx_adap)
 153                cec_received_msg(dev->cec_rx_adap, &cw->msg);
 154        for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
 155                if (adap != dev->cec_tx_adap[i])
 156                        cec_received_msg(dev->cec_tx_adap[i], &cw->msg);
 157        kfree(cw);
 158}
 159
 160static void vivid_cec_xfer_try_worker(struct work_struct *work)
 161{
 162        struct vivid_cec_work *cw =
 163                container_of(work, struct vivid_cec_work, work.work);
 164        struct vivid_dev *dev = cw->dev;
 165
 166        spin_lock(&dev->cec_slock);
 167        if (dev->cec_xfer_time_jiffies) {
 168                list_del(&cw->list);
 169                spin_unlock(&dev->cec_slock);
 170                cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_ARB_LOST);
 171                kfree(cw);
 172        } else {
 173                INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
 174                dev->cec_xfer_start_jiffies = jiffies;
 175                dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
 176                spin_unlock(&dev->cec_slock);
 177                schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies);
 178        }
 179}
 180
 181static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
 182{
 183        adap->cec_pin_is_high = true;
 184        return 0;
 185}
 186
 187static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
 188{
 189        return 0;
 190}
 191
 192/*
 193 * One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us
 194 * per byte.
 195 */
 196#define USECS_PER_BYTE 24000
 197
 198static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
 199                                   u32 signal_free_time, struct cec_msg *msg)
 200{
 201        struct vivid_dev *dev = cec_get_drvdata(adap);
 202        struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL);
 203        long delta_jiffies = 0;
 204
 205        if (cw == NULL)
 206                return -ENOMEM;
 207        cw->dev = dev;
 208        cw->adap = adap;
 209        cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) +
 210                    msg->len * USECS_PER_BYTE;
 211        cw->msg = *msg;
 212
 213        spin_lock(&dev->cec_slock);
 214        list_add(&cw->list, &dev->cec_work_list);
 215        if (dev->cec_xfer_time_jiffies == 0) {
 216                INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
 217                dev->cec_xfer_start_jiffies = jiffies;
 218                dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
 219                delta_jiffies = dev->cec_xfer_time_jiffies;
 220        } else {
 221                INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker);
 222                delta_jiffies = dev->cec_xfer_start_jiffies +
 223                        dev->cec_xfer_time_jiffies - jiffies;
 224        }
 225        spin_unlock(&dev->cec_slock);
 226        schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies);
 227        return 0;
 228}
 229
 230static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
 231{
 232        struct vivid_dev *dev = cec_get_drvdata(adap);
 233        struct cec_msg reply;
 234        u8 dest = cec_msg_destination(msg);
 235        u8 disp_ctl;
 236        char osd[14];
 237
 238        if (cec_msg_is_broadcast(msg))
 239                dest = adap->log_addrs.log_addr[0];
 240        cec_msg_init(&reply, dest, cec_msg_initiator(msg));
 241
 242        switch (cec_msg_opcode(msg)) {
 243        case CEC_MSG_SET_OSD_STRING:
 244                if (!cec_is_sink(adap))
 245                        return -ENOMSG;
 246                cec_ops_set_osd_string(msg, &disp_ctl, osd);
 247                switch (disp_ctl) {
 248                case CEC_OP_DISP_CTL_DEFAULT:
 249                        strcpy(dev->osd, osd);
 250                        dev->osd_jiffies = jiffies;
 251                        break;
 252                case CEC_OP_DISP_CTL_UNTIL_CLEARED:
 253                        strcpy(dev->osd, osd);
 254                        dev->osd_jiffies = 0;
 255                        break;
 256                case CEC_OP_DISP_CTL_CLEAR:
 257                        dev->osd[0] = 0;
 258                        dev->osd_jiffies = 0;
 259                        break;
 260                default:
 261                        cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
 262                                              CEC_OP_ABORT_INVALID_OP);
 263                        cec_transmit_msg(adap, &reply, false);
 264                        break;
 265                }
 266                break;
 267        default:
 268                return -ENOMSG;
 269        }
 270        return 0;
 271}
 272
 273static const struct cec_adap_ops vivid_cec_adap_ops = {
 274        .adap_enable = vivid_cec_adap_enable,
 275        .adap_log_addr = vivid_cec_adap_log_addr,
 276        .adap_transmit = vivid_cec_adap_transmit,
 277        .received = vivid_received,
 278};
 279
 280struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
 281                                         unsigned int idx,
 282                                         bool is_source)
 283{
 284        char name[sizeof(dev->vid_out_dev.name) + 2];
 285        u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
 286
 287        snprintf(name, sizeof(name), "%s%d",
 288                 is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name,
 289                 idx);
 290        return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
 291                name, caps, 1);
 292}
 293