datasize = 4;
                        break;
                case MCE_CMD_G_REVISION:
-                       datasize = 2;
+                       datasize = 4;
                        break;
                case MCE_RSP_EQWAKESUPPORT:
                case MCE_RSP_GETWAKESOURCE:
        char *inout;
        u8 cmd, subcmd, *data;
        struct device *dev = ir->dev;
-       int start, skip = 0;
        u32 carrier, period;
 
-       /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
-       if (ir->flags.microsoft_gen1 && !out && !offset)
-               skip = 2;
-
-       if (len <= skip)
+       if (offset < 0 || offset >= buf_len)
                return;
 
        dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)",
 
        inout = out ? "Request" : "Got";
 
-       start  = offset + skip;
-       cmd    = buf[start] & 0xff;
-       subcmd = buf[start + 1] & 0xff;
-       data = buf + start + 2;
+       cmd    = buf[offset];
+       subcmd = (offset + 1 < buf_len) ? buf[offset + 1] : 0;
+       data   = &buf[offset] + 2;
+
+       /* Trace meaningless 0xb1 0x60 header bytes on original receiver */
+       if (ir->flags.microsoft_gen1 && !out && !offset) {
+               dev_dbg(dev, "MCE gen 1 header");
+               return;
+       }
+
+       /* Trace IR data header or trailer */
+       if (cmd != MCE_CMD_PORT_IR &&
+           (cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA) {
+               if (cmd == MCE_IRDATA_TRAILER)
+                       dev_dbg(dev, "End of raw IR data");
+               else
+                       dev_dbg(dev, "Raw IR data, %d pulse/space samples",
+                               cmd & MCE_PACKET_LENGTH_MASK);
+               return;
+       }
+
+       /* Unexpected end of buffer? */
+       if (offset + len > buf_len)
+               return;
 
+       /* Decode MCE command/response */
        switch (cmd) {
        case MCE_CMD_NULL:
                if (subcmd == MCE_CMD_NULL)
                                dev_dbg(dev, "Get hw/sw rev?");
                        else
                                dev_dbg(dev, "hw/sw rev %*ph",
-                                       4, &buf[start + 2]);
+                                       4, &buf[offset + 2]);
                        break;
                case MCE_CMD_RESUME:
                        dev_dbg(dev, "Device resume requested");
        default:
                break;
        }
-
-       if (cmd == MCE_IRDATA_TRAILER)
-               dev_dbg(dev, "End of raw IR data");
-       else if ((cmd != MCE_CMD_PORT_IR) &&
-                ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
-               dev_dbg(dev, "Raw IR data, %d pulse/space samples",
-                       cmd & MCE_PACKET_LENGTH_MASK);
 #endif
 }
 
 }
 
 /*
+ * Handle PORT_SYS/IR command response received from the MCE device.
+ *
+ * Assumes single response with all its data (not truncated)
+ * in buf_in[]. The response itself determines its total length
+ * (mceusb_cmd_datasize() + 2) and hence the minimum size of buf_in[].
+ *
  * We don't do anything but print debug spew for many of the command bits
  * we receive from the hardware, but some of them are useful information
  * we want to store so that we can use them.
  */
-static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
 {
+       u8 cmd = buf_in[0];
+       u8 subcmd = buf_in[1];
+       u8 *hi = &buf_in[2];            /* read only when required */
+       u8 *lo = &buf_in[3];            /* read only when required */
        struct ir_raw_event rawir = {};
-       u8 hi = ir->buf_in[index + 1] & 0xff;
-       u8 lo = ir->buf_in[index + 2] & 0xff;
        u32 carrier_cycles;
        u32 cycles_fix;
 
-       switch (ir->buf_in[index]) {
-       /* the one and only 5-byte return value command */
-       case MCE_RSP_GETPORTSTATUS:
-               if ((ir->buf_in[index + 4] & 0xff) == 0x00)
-                       ir->txports_cabled |= 1 << hi;
-               break;
+       if (cmd == MCE_CMD_PORT_SYS) {
+               switch (subcmd) {
+               /* the one and only 5-byte return value command */
+               case MCE_RSP_GETPORTSTATUS:
+                       if (buf_in[5] == 0)
+                               ir->txports_cabled |= 1 << *hi;
+                       break;
+
+               /* 1-byte return value commands */
+               case MCE_RSP_EQEMVER:
+                       ir->emver = *hi;
+                       break;
+
+               /* No return value commands */
+               case MCE_RSP_CMD_ILLEGAL:
+                       ir->need_reset = true;
+                       break;
+
+               default:
+                       break;
+               }
+
+               return;
+       }
 
+       if (cmd != MCE_CMD_PORT_IR)
+               return;
+
+       switch (subcmd) {
        /* 2-byte return value commands */
        case MCE_RSP_EQIRTIMEOUT:
-               ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
+               ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT);
                break;
        case MCE_RSP_EQIRNUMPORTS:
-               ir->num_txports = hi;
-               ir->num_rxports = lo;
+               ir->num_txports = *hi;
+               ir->num_rxports = *lo;
                break;
        case MCE_RSP_EQIRRXCFCNT:
                /*
                 */
                if (ir->carrier_report_enabled && ir->learning_active &&
                    ir->pulse_tunit > 0) {
-                       carrier_cycles = (hi << 8 | lo);
+                       carrier_cycles = (*hi << 8 | *lo);
                        /*
                         * Adjust carrier cycle count by adding
                         * 1 missed count per pulse "on"
                break;
 
        /* 1-byte return value commands */
-       case MCE_RSP_EQEMVER:
-               ir->emver = hi;
-               break;
        case MCE_RSP_EQIRTXPORTS:
-               ir->tx_mask = hi;
+               ir->tx_mask = *hi;
                break;
        case MCE_RSP_EQIRRXPORTEN:
-               ir->learning_active = ((hi & 0x02) == 0x02);
-               if (ir->rxports_active != hi) {
+               ir->learning_active = ((*hi & 0x02) == 0x02);
+               if (ir->rxports_active != *hi) {
                        dev_info(ir->dev, "%s-range (0x%x) receiver active",
-                                ir->learning_active ? "short" : "long", hi);
-                       ir->rxports_active = hi;
+                                ir->learning_active ? "short" : "long", *hi);
+                       ir->rxports_active = *hi;
                }
                break;
+
+       /* No return value commands */
        case MCE_RSP_CMD_ILLEGAL:
        case MCE_RSP_TX_TIMEOUT:
                ir->need_reset = true;
                break;
+
        default:
                break;
        }
                        ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
                        mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1,
                                             ir->rem + 2, false);
-                       mceusb_handle_command(ir, i);
+                       if (i + ir->rem < buf_len)
+                               mceusb_handle_command(ir, &ir->buf_in[i - 1]);
                        ir->parser_state = CMD_DATA;
                        break;
                case PARSE_IRDATA:
                        ir->rem--;
                        break;
                case CMD_HEADER:
-                       /* decode mce packets of the form (84),AA,BB,CC,DD */
-                       /* IR data packets can span USB messages - rem */
                        ir->cmd = ir->buf_in[i];
                        if ((ir->cmd == MCE_CMD_PORT_IR) ||
                            ((ir->cmd & MCE_PORT_MASK) !=
                             MCE_COMMAND_IRDATA)) {
+                               /*
+                                * got PORT_SYS, PORT_IR, or unknown
+                                * command response prefix
+                                */
                                ir->parser_state = SUBCMD;
                                continue;
                        }
+                       /*
+                        * got IR data prefix (0x80 + num_bytes)
+                        * decode MCE packets of the form {0x83, AA, BB, CC}
+                        * IR data packets can span USB messages
+                        */
                        ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
                        mceusb_dev_printdata(ir, ir->buf_in, buf_len,
                                             i, ir->rem + 1, false);
                if (ir->parser_state != CMD_HEADER && !ir->rem)
                        ir->parser_state = CMD_HEADER;
        }
+
+       /*
+        * Accept IR data spanning multiple rx buffers.
+        * Reject MCE command response spanning multiple rx buffers.
+        */
+       if (ir->parser_state != PARSE_IRDATA || !ir->rem)
+               ir->parser_state = CMD_HEADER;
+
        if (event) {
                dev_dbg(ir->dev, "processed IR data");
                ir_raw_event_handle(ir->rc);