media: pulse8-cec: fix lost cec_transmit_attempt_done() call
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Sat, 7 Dec 2019 22:43:23 +0000 (23:43 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2020 09:17:54 +0000 (10:17 +0100)
commit e5a52a1d15c79bb48a430fb263852263ec1d3f11 upstream.

The periodic PING command could interfere with the result of
a CEC transmit, causing a lost cec_transmit_attempt_done()
call.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Cc: <stable@vger.kernel.org> # for v4.10 and up
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/usb/pulse8-cec/pulse8-cec.c

index 12da631c0fda0437b8e477c9ec3a7f8e36b2997c..f1615fb60015111a208d19140ecb910ab218a67a 100644 (file)
@@ -121,6 +121,7 @@ struct pulse8 {
        unsigned int vers;
        struct completion cmd_done;
        struct work_struct work;
+       u8 work_result;
        struct delayed_work ping_eeprom_work;
        struct cec_msg rx_msg;
        u8 data[DATA_SIZE];
@@ -142,8 +143,10 @@ static void pulse8_irq_work_handler(struct work_struct *work)
 {
        struct pulse8 *pulse8 =
                container_of(work, struct pulse8, work);
+       u8 result = pulse8->work_result;
 
-       switch (pulse8->data[0] & 0x3f) {
+       pulse8->work_result = 0;
+       switch (result & 0x3f) {
        case MSGCODE_FRAME_DATA:
                cec_received_msg(pulse8->adap, &pulse8->rx_msg);
                break;
@@ -177,12 +180,12 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
                pulse8->escape = false;
        } else if (data == MSGEND) {
                struct cec_msg *msg = &pulse8->rx_msg;
+               u8 msgcode = pulse8->buf[0];
 
                if (debug)
                        dev_info(pulse8->dev, "received: %*ph\n",
                                 pulse8->idx, pulse8->buf);
-               pulse8->data[0] = pulse8->buf[0];
-               switch (pulse8->buf[0] & 0x3f) {
+               switch (msgcode & 0x3f) {
                case MSGCODE_FRAME_START:
                        msg->len = 1;
                        msg->msg[0] = pulse8->buf[1];
@@ -191,14 +194,20 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
                        if (msg->len == CEC_MAX_MSG_SIZE)
                                break;
                        msg->msg[msg->len++] = pulse8->buf[1];
-                       if (pulse8->buf[0] & MSGCODE_FRAME_EOM)
+                       if (msgcode & MSGCODE_FRAME_EOM) {
+                               WARN_ON(pulse8->work_result);
+                               pulse8->work_result = msgcode;
                                schedule_work(&pulse8->work);
+                               break;
+                       }
                        break;
                case MSGCODE_TRANSMIT_SUCCEEDED:
                case MSGCODE_TRANSMIT_FAILED_LINE:
                case MSGCODE_TRANSMIT_FAILED_ACK:
                case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
                case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
+                       WARN_ON(pulse8->work_result);
+                       pulse8->work_result = msgcode;
                        schedule_work(&pulse8->work);
                        break;
                case MSGCODE_HIGH_ERROR: