linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] mceusb updates per MS docs
@ 2011-07-14 22:09 Jarod Wilson
  2011-07-14 22:09 ` [PATCH 1/9] [media] mceusb: command/response updates from " Jarod Wilson
                   ` (18 more replies)
  0 siblings, 19 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

This is a stack of updates made based on the Windows Media Center remote
and receiver/transmitter specification and requirements document that
Rafi Rubin recently pointed me at. Its titled
Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
which as of this writing, is publicly available from
download.microsoft.com.

Tested with 7 different mceusb devices, with no ill effects. Unfortunately,
for the most part, these chagnes don't actually improve any shortcomings in
the driver, but they do give us a better view of the hardware features and
whatnot, and a few things are better explained now, with most of the command
and response bits lining up with what MS has documented.

Jarod Wilson (9):
  [media] mceusb: command/response updates from MS docs
  [media] mceusb: give hardware time to reply to cmds
  [media] mceusb: set wakeup bits for IR-based resume
  [media] mceusb: issue device resume cmd when needed
  [media] mceusb: query device for firmware emulator version
  [media] mceusb: get misc port data from hardware
  [media] mceusb: flash LED (emu v2+ only) to signal end of init
  [media] mceusb: report actual tx frequencies
  [media] mceusb: update version, copyright, author

 drivers/media/rc/mceusb.c |  422 ++++++++++++++++++++++++++++++---------------
 1 files changed, 286 insertions(+), 136 deletions(-)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/9] [media] mceusb: command/response updates from MS docs
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

I was recently pointed to the document titled
Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
which as of this writing, is publicly available from
download.microsoft.com. It covers a LOT of the gaps in the mceusb
driver, which to this point, was written almost entirely by
reverse-engineering. First up, I'm updating the defines for all the MCE
commands and responses to match their names in the spec. More to come...

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |  293 ++++++++++++++++++++++++++------------------
 1 files changed, 173 insertions(+), 120 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index ec972dc..111bead 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -63,43 +63,90 @@
 #define MCE_PULSE_MASK		0x7f /* Pulse mask */
 #define MCE_MAX_PULSE_LENGTH	0x7f /* Longest transmittable pulse symbol */
 
-#define MCE_HW_CMD_HEADER	0xff	/* MCE hardware command header */
-#define MCE_COMMAND_HEADER	0x9f	/* MCE command header */
-#define MCE_COMMAND_MASK	0xe0	/* Mask out command bits */
-#define MCE_COMMAND_NULL	0x00	/* These show up various places... */
-/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
- * then we're looking at a raw IR data sample */
-#define MCE_COMMAND_IRDATA	0x80
-#define MCE_PACKET_LENGTH_MASK	0x1f /* Packet length mask */
-
-/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+/*
+ * The interface between the host and the IR hardware is command-response
+ * based. All commands and responses have a consistent format, where a lead
+ * byte always identifies the type of data following it. The lead byte has
+ * a port value in the 3 highest bits and a length value in the 5 lowest
+ * bits.
+ *
+ * The length field is overloaded, with a value of 11111 indicating that the
+ * following byte is a command or response code, and the length of the entire
+ * message is determined by the code. If the length field is not 11111, then
+ * it specifies the number of bytes of port data that follow.
+ */
+#define MCE_CMD			0x1f
+#define MCE_PORT_IR		0x4	/* (0x4 << 5) | MCE_CMD = 0x9f */
+#define MCE_PORT_SYS		0x7	/* (0x7 << 5) | MCE_CMD = 0xff */
+#define MCE_PORT_SER		0x6	/* 0xc0 thru 0xdf flush & 0x1f bytes */
+#define MCE_PORT_MASK	0xe0	/* Mask out command bits */
+
+/* Command port headers */
+#define MCE_CMD_PORT_IR		0x9f	/* IR-related cmd/rsp */
+#define MCE_CMD_PORT_SYS	0xff	/* System (non-IR) device cmd/rsp */
+
+/* Commands that set device state  (2-4 bytes in length) */
+#define MCE_CMD_RESET		0xfe	/* Reset device, 2 bytes */
+#define MCE_CMD_RESUME		0xaa	/* Resume device after error, 2 bytes */
+#define MCE_CMD_SETIRCFS	0x06	/* Set tx carrier, 4 bytes */
+#define MCE_CMD_SETIRTIMEOUT	0x0c	/* Set timeout, 4 bytes */
+#define MCE_CMD_SETIRTXPORTS	0x08	/* Set tx ports, 3 bytes */
+#define MCE_CMD_SETIRRXPORTEN	0x14	/* Set rx ports, 3 bytes */
+#define MCE_CMD_FLASHLED	0x23	/* Flash receiver LED, 2 bytes */
+
+/* Commands that query device state (all 2 bytes, unless noted) */
+#define MCE_CMD_GETIRCFS	0x07	/* Get carrier */
+#define MCE_CMD_GETIRTIMEOUT	0x0d	/* Get timeout */
+#define MCE_CMD_GETIRTXPORTS	0x13	/* Get tx ports */
+#define MCE_CMD_GETIRRXPORTEN	0x15	/* Get rx ports */
+#define MCE_CMD_GETPORTSTATUS	0x11	/* Get tx port status, 3 bytes */
+#define MCE_CMD_GETIRNUMPORTS	0x16	/* Get number of ports */
+#define MCE_CMD_GETWAKESOURCE	0x17	/* Get wake source */
+#define MCE_CMD_GETEMVER	0x22	/* Get emulator interface version */
+#define MCE_CMD_GETDEVDETAILS	0x21	/* Get device details (em ver2 only) */
+#define MCE_CMD_GETWAKESUPPORT	0x20	/* Get wake details (em ver2 only) */
+#define MCE_CMD_GETWAKEVERSION	0x18	/* Get wake pattern (em ver2 only) */
+
+/* Misc commands */
+#define MCE_CMD_NOP		0xff	/* No operation */
+
+/* Responses to commands (non-error cases) */
+#define MCE_RSP_EQIRCFS		0x06	/* tx carrier, 4 bytes */
+#define MCE_RSP_EQIRTIMEOUT	0x0c	/* rx timeout, 4 bytes */
+#define MCE_RSP_GETWAKESOURCE	0x17	/* wake source, 3 bytes */
+#define MCE_RSP_EQIRTXPORTS	0x08	/* tx port mask, 3 bytes */
+#define MCE_RSP_EQIRRXPORTEN	0x14	/* rx port mask, 3 bytes */
+#define MCE_RSP_GETPORTSTATUS	0x11	/* tx port status, 7 bytes */
+#define MCE_RSP_EQIRRXCFCNT	0x15	/* rx carrier count, 4 bytes */
+#define MCE_RSP_EQIRNUMPORTS	0x16	/* number of ports, 4 bytes */
+#define MCE_RSP_EQWAKESUPPORT	0x20	/* wake capabilities, 3 bytes */
+#define MCE_RSP_EQWAKEVERSION	0x18	/* wake pattern details, 6 bytes */
+#define MCE_RSP_EQDEVDETAILS	0x21	/* device capabilities, 3 bytes */
+#define MCE_RSP_EQEMVER		0x22	/* emulator interface ver, 3 bytes */
+#define MCE_RSP_FLASHLED	0x23	/* success flashing LED, 2 bytes */
+
+/* Responses to error cases, must send MCE_CMD_RESUME to clear them */
+#define MCE_RSP_CMD_ILLEGAL	0xfe	/* illegal command for port, 2 bytes */
+#define MCE_RSP_TX_TIMEOUT	0x81	/* tx timed out, 2 bytes */
+
+/* Misc commands/responses not defined in the MCE remote/transceiver spec */
 #define MCE_CMD_SIG_END		0x01	/* End of signal */
 #define MCE_CMD_PING		0x03	/* Ping device */
 #define MCE_CMD_UNKNOWN		0x04	/* Unknown */
 #define MCE_CMD_UNKNOWN2	0x05	/* Unknown */
-#define MCE_CMD_S_CARRIER	0x06	/* Set TX carrier frequency */
-#define MCE_CMD_G_CARRIER	0x07	/* Get TX carrier frequency */
-#define MCE_CMD_S_TXMASK	0x08	/* Set TX port bitmask */
 #define MCE_CMD_UNKNOWN3	0x09	/* Unknown */
 #define MCE_CMD_UNKNOWN4	0x0a	/* Unknown */
 #define MCE_CMD_G_REVISION	0x0b	/* Get hw/sw revision */
-#define MCE_CMD_S_TIMEOUT	0x0c	/* Set RX timeout value */
-#define MCE_CMD_G_TIMEOUT	0x0d	/* Get RX timeout value */
 #define MCE_CMD_UNKNOWN5	0x0e	/* Unknown */
 #define MCE_CMD_UNKNOWN6	0x0f	/* Unknown */
-#define MCE_CMD_G_RXPORTSTS	0x11	/* Get RX port status */
-#define MCE_CMD_G_TXMASK	0x13	/* Set TX port bitmask */
-#define MCE_CMD_S_RXSENSOR	0x14	/* Set RX sensor (std/learning) */
-#define MCE_CMD_G_RXSENSOR	0x15	/* Get RX sensor (std/learning) */
-#define MCE_RSP_PULSE_COUNT	0x15	/* RX pulse count (only if learning) */
-#define MCE_CMD_TX_PORTS	0x16	/* Get number of TX ports */
-#define MCE_CMD_G_WAKESRC	0x17	/* Get wake source */
-#define MCE_CMD_UNKNOWN7	0x18	/* Unknown */
 #define MCE_CMD_UNKNOWN8	0x19	/* Unknown */
 #define MCE_CMD_UNKNOWN9	0x1b	/* Unknown */
-#define MCE_CMD_DEVICE_RESET	0xaa	/* Reset the hardware */
-#define MCE_RSP_CMD_INVALID	0xfe	/* Invalid command issued */
+#define MCE_CMD_NULL		0x00	/* These show up various places... */
 
+/* if buf[i] & MCE_PORT_MASK == 0x80 and buf[i] != MCE_CMD_PORT_IR,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA	0x80
+#define MCE_PACKET_LENGTH_MASK	0x1f /* Packet length mask */
 
 /* module parameters */
 #ifdef CONFIG_USB_DEBUG
@@ -390,46 +437,25 @@ struct mceusb_dev {
 	enum mceusb_model_type model;
 };
 
-/*
- * MCE Device Command Strings
- * Device command responses vary from device to device...
- * - DEVICE_RESET resets the hardware to its default state
- * - GET_REVISION fetches the hardware/software revision, common
- *   replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
- * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
- *   device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
- *   meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
- *   ((clk / frequency) - 1)
- * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
- *   response in the form of 9f 0c msb lsb
- * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
- *   the form of 9f 08 bm, where bm is the bitmask
- * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
- *   general use one or short-range learning one, in the form of
- *   9f 14 ss, where ss is either 01 for long-range or 02 for short
- * - SET_CARRIER_FREQ sets a new carrier mode and frequency
- * - SET_TX_BITMASK sets the transmitter bitmask
- * - SET_RX_TIMEOUT sets the receiver timeout
- * - SET_RX_SENSOR sets which receiver sensor to use
- */
-static char DEVICE_RESET[]	= {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
-				   MCE_CMD_DEVICE_RESET};
-static char GET_REVISION[]	= {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
-static char GET_UNKNOWN[]	= {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
-static char GET_UNKNOWN2[]	= {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
-static char GET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
-static char GET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
-static char GET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
-static char GET_RX_SENSOR[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
+/* MCE Device Command Strings, generally a port and command pair */
+static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
+				   MCE_CMD_RESUME};
+static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
+static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
+static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
+static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
+static char GET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS};
+static char GET_RX_SENSOR[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN};
 /* sub in desired values in lower byte or bytes for full command */
 /* FIXME: make use of these for transmit.
-static char SET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_CARRIER, 0x00, 0x00};
-static char SET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
-static char SET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_TIMEOUT, 0x00, 0x00};
-static char SET_RX_SENSOR[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_RXSENSOR, 0x00};
+static char SET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR,
+				   MCE_CMD_SETIRCFS, 0x00, 0x00};
+static char SET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_SETIRTXPORTS, 0x00};
+static char SET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR,
+				   MCE_CMD_SETIRTIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[]	= {MCE_CMD_PORT_IR,
+				   MCE_RSP_EQIRRXPORTEN, 0x00};
 */
 
 static int mceusb_cmdsize(u8 cmd, u8 subcmd)
@@ -437,27 +463,33 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
 	int datasize = 0;
 
 	switch (cmd) {
-	case MCE_COMMAND_NULL:
-		if (subcmd == MCE_HW_CMD_HEADER)
+	case MCE_CMD_NULL:
+		if (subcmd == MCE_CMD_PORT_SYS)
 			datasize = 1;
 		break;
-	case MCE_HW_CMD_HEADER:
+	case MCE_CMD_PORT_SYS:
 		switch (subcmd) {
+		case MCE_RSP_EQWAKEVERSION:
+			datasize = 4;
+			break;
 		case MCE_CMD_G_REVISION:
 			datasize = 2;
 			break;
+		case MCE_RSP_EQWAKESUPPORT:
+			datasize = 1;
+			break;
 		}
-	case MCE_COMMAND_HEADER:
+	case MCE_CMD_PORT_IR:
 		switch (subcmd) {
 		case MCE_CMD_UNKNOWN:
-		case MCE_CMD_S_CARRIER:
-		case MCE_CMD_S_TIMEOUT:
-		case MCE_RSP_PULSE_COUNT:
+		case MCE_RSP_EQIRCFS:
+		case MCE_RSP_EQIRTIMEOUT:
+		case MCE_RSP_EQIRRXCFCNT:
 			datasize = 2;
 			break;
 		case MCE_CMD_SIG_END:
-		case MCE_CMD_S_TXMASK:
-		case MCE_CMD_S_RXSENSOR:
+		case MCE_RSP_EQIRTXPORTS:
+		case MCE_RSP_EQIRRXPORTEN:
 			datasize = 1;
 			break;
 		}
@@ -470,7 +502,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 {
 	char codes[USB_BUFLEN * 3 + 1];
 	char inout[9];
-	u8 cmd, subcmd, data1, data2;
+	u8 cmd, subcmd, data1, data2, data3, data4, data5;
 	struct device *dev = ir->dev;
 	int i, start, skip = 0;
 
@@ -500,18 +532,26 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 	subcmd = buf[start + 1] & 0xff;
 	data1  = buf[start + 2] & 0xff;
 	data2  = buf[start + 3] & 0xff;
+	data3  = buf[start + 4] & 0xff;
+	data4  = buf[start + 5] & 0xff;
+	data5  = buf[start + 6] & 0xff;
 
 	switch (cmd) {
-	case MCE_COMMAND_NULL:
-		if ((subcmd == MCE_HW_CMD_HEADER) &&
-		    (data1 == MCE_CMD_DEVICE_RESET))
-			dev_info(dev, "Device reset requested\n");
+	case MCE_CMD_NULL:
+		if ((subcmd == MCE_CMD_PORT_SYS) &&
+		    (data1 == MCE_CMD_RESUME))
+			dev_info(dev, "Device resume requested\n");
 		else
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 		break;
-	case MCE_HW_CMD_HEADER:
+	case MCE_CMD_PORT_SYS:
 		switch (subcmd) {
+		case MCE_RSP_EQEMVER:
+			if (!out)
+				dev_info(dev, "Emulator interface version %x\n",
+					 data1);
+			break;
 		case MCE_CMD_G_REVISION:
 			if (len == 2)
 				dev_info(dev, "Get hw/sw rev?\n");
@@ -520,21 +560,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 					 "0x%02x 0x%02x\n", data1, data2,
 					 buf[start + 4], buf[start + 5]);
 			break;
-		case MCE_CMD_DEVICE_RESET:
-			dev_info(dev, "Device reset requested\n");
+		case MCE_CMD_RESUME:
+			dev_info(dev, "Device resume requested\n");
+			break;
+		case MCE_RSP_CMD_ILLEGAL:
+			dev_info(dev, "Illegal PORT_SYS command\n");
+			break;
+		case MCE_RSP_EQWAKEVERSION:
+			if (!out)
+				dev_info(dev, "Wake version, proto: 0x%02x, "
+					 "payload: 0x%02x, address: 0x%02x, "
+					 "version: 0x%02x\n",
+					 data1, data2, data3, data4);
 			break;
-		case MCE_RSP_CMD_INVALID:
-			dev_info(dev, "Previous command not supported\n");
+		case MCE_RSP_GETPORTSTATUS:
+			if (!out)
+				/* We use data1 + 1 here, to match hw labels */
+				dev_info(dev, "TX port %d: blaster is%s connected\n",
+					 data1 + 1, data4 ? " not" : "");
 			break;
-		case MCE_CMD_UNKNOWN7:
-		case MCE_CMD_UNKNOWN9:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 			break;
 		}
 		break;
-	case MCE_COMMAND_HEADER:
+	case MCE_CMD_PORT_IR:
 		switch (subcmd) {
 		case MCE_CMD_SIG_END:
 			dev_info(dev, "End of signal\n");
@@ -546,47 +597,50 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
 				 data1, data2);
 			break;
-		case MCE_CMD_S_CARRIER:
+		case MCE_CMD_SETIRCFS:
 			dev_info(dev, "%s carrier mode and freq of "
 				 "0x%02x 0x%02x\n", inout, data1, data2);
 			break;
-		case MCE_CMD_G_CARRIER:
+		case MCE_CMD_GETIRCFS:
 			dev_info(dev, "Get carrier mode and freq\n");
 			break;
-		case MCE_CMD_S_TXMASK:
+		case MCE_RSP_EQIRTXPORTS:
 			dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
 				 inout, data1);
 			break;
-		case MCE_CMD_S_TIMEOUT:
+		case MCE_RSP_EQIRTIMEOUT:
 			/* value is in units of 50us, so x*50/1000 ms */
 			dev_info(dev, "%s receive timeout of %d ms\n",
 				 inout,
 				 ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000);
 			break;
-		case MCE_CMD_G_TIMEOUT:
+		case MCE_CMD_GETIRTIMEOUT:
 			dev_info(dev, "Get receive timeout\n");
 			break;
-		case MCE_CMD_G_TXMASK:
+		case MCE_CMD_GETIRTXPORTS:
 			dev_info(dev, "Get transmit blaster mask\n");
 			break;
-		case MCE_CMD_S_RXSENSOR:
+		case MCE_RSP_EQIRRXPORTEN:
 			dev_info(dev, "%s %s-range receive sensor in use\n",
 				 inout, data1 == 0x02 ? "short" : "long");
 			break;
-		case MCE_CMD_G_RXSENSOR:
-		/* aka MCE_RSP_PULSE_COUNT */
+		case MCE_CMD_GETIRRXPORTEN:
+		/* aka MCE_RSP_EQIRRXCFCNT */
 			if (out)
 				dev_info(dev, "Get receive sensor\n");
 			else if (ir->learning_enabled)
 				dev_info(dev, "RX pulse count: %d\n",
 					 ((data1 << 8) | data2));
 			break;
-		case MCE_RSP_CMD_INVALID:
-			dev_info(dev, "Error! Hardware is likely wedged...\n");
+		case MCE_RSP_EQIRNUMPORTS:
+			if (out)
+				break;
+			dev_info(dev, "Num TX ports: %x, num RX ports: %x\n",
+				 data1, data2);
+			break;
+		case MCE_RSP_CMD_ILLEGAL:
+			dev_info(dev, "Illegal PORT_IR command\n");
 			break;
-		case MCE_CMD_UNKNOWN2:
-		case MCE_CMD_UNKNOWN3:
-		case MCE_CMD_UNKNOWN5:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
@@ -599,8 +653,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 
 	if (cmd == MCE_IRDATA_TRAILER)
 		dev_info(dev, "End of raw IR data\n");
-	else if ((cmd != MCE_COMMAND_HEADER) &&
-		 ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+	else if ((cmd != MCE_CMD_PORT_IR) &&
+		 ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
 		dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
 }
 
@@ -616,9 +670,6 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
 	if (ir) {
 		len = urb->actual_length;
 
-		mce_dbg(ir->dev, "callback called (status=%d len=%d)\n",
-			urb->status, len);
-
 		mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
 	}
 
@@ -710,8 +761,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 		return -ENOMEM;
 
 	/* MCE tx init header */
-	cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
-	cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
+	cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
+	cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS;
 	cmdbuf[cmdcount++] = ir->tx_mask;
 
 	/* Generate mce packet data */
@@ -797,8 +848,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
 	struct mceusb_dev *ir = dev->priv;
 	int clk = 10000000;
 	int prescaler = 0, divisor = 0;
-	unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
-				    MCE_CMD_S_CARRIER, 0x00, 0x00 };
+	unsigned char cmdbuf[4] = { MCE_CMD_PORT_IR,
+				    MCE_CMD_SETIRCFS, 0x00, 0x00 };
 
 	/* Carrier has changed */
 	if (ir->carrier != carrier) {
@@ -847,16 +898,16 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 
 	switch (ir->buf_in[index]) {
 	/* 2-byte return value commands */
-	case MCE_CMD_S_TIMEOUT:
+	case MCE_RSP_EQIRTIMEOUT:
 		ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
 		break;
 
 	/* 1-byte return value commands */
-	case MCE_CMD_S_TXMASK:
+	case MCE_RSP_EQIRTXPORTS:
 		ir->tx_mask = hi;
 		break;
-	case MCE_CMD_S_RXSENSOR:
-		ir->learning_enabled = (hi == 0x02);
+	case MCE_RSP_EQIRRXPORTEN:
+		ir->learning_enabled = ((hi & 0x02) == 0x02);
 		break;
 	default:
 		break;
@@ -905,8 +956,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 			/* 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_COMMAND_HEADER) ||
-			    ((ir->cmd & MCE_COMMAND_MASK) !=
+			if ((ir->cmd == MCE_CMD_PORT_IR) ||
+			    ((ir->cmd & MCE_PORT_MASK) !=
 			     MCE_COMMAND_IRDATA)) {
 				ir->parser_state = SUBCMD;
 				continue;
@@ -1013,8 +1064,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 			      0x0000, 0x0100, NULL, 0, HZ * 3);
 	mce_dbg(dev, "%s - retC = %d\n", __func__, ret);
 
-	/* device reset */
-	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	/* device resume */
+	mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
 	/* get hw/sw revision? */
 	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
@@ -1024,14 +1075,16 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
 {
-	/* device reset */
-	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	/* device resume */
+	mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
 	/* get hw/sw revision? */
 	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
 
-	/* unknown what the next two actually return... */
-	mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+	/* get wake version (protocol, key, address) */
+	mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION));
+
+	/* unknown what this one actually returns... */
 	mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
 }
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
  2011-07-14 22:09 ` [PATCH 1/9] [media] mceusb: command/response updates from " Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 23:30   ` Mauro Carvalho Chehab
  2011-07-14 22:09 ` [PATCH 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Sometimes the init routine is blasting commands out to the hardware
faster than it can reply. Throw a brief delay in there to give the
hardware a chance to reply before we send the next command.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 111bead..13a853b 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
+#include <linux/delay.h>
 #include <media/rc-core.h>
 
 #define DRIVER_VERSION	"1.91"
@@ -735,6 +736,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
 	mce_request_packet(ir, data, size, MCEUSB_TX);
+	mdelay(10);
 }
 
 static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 3/9] [media] mceusb: set wakeup bits for IR-based resume
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
  2011-07-14 22:09 ` [PATCH 1/9] [media] mceusb: command/response updates from " Jarod Wilson
  2011-07-14 22:09 ` [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Its not uncommon for folks to force these bits enabled, because people
do want to wake their htpc kit via their remote. Lets just set the bits
for 'em.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 13a853b..7ff755f 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
+#include <linux/pm_wakeup.h>
 #include <linux/delay.h>
 #include <media/rc-core.h>
 
@@ -1290,6 +1291,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, ir);
 
+	/* enable wake via this device */
+	device_set_wakeup_capable(ir->dev, true);
+	device_set_wakeup_enable(ir->dev, true);
+
 	dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
 		 dev->bus->busnum, dev->devnum);
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 4/9] [media] mceusb: issue device resume cmd when needed
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (2 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

According to MS docs, the device firmware may halt after receiving an
unknown instruction, but that it should be possible to tell the firmware
to continue running by simply sending a device resume command. So lets
do that.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 7ff755f..a777623 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -437,6 +437,8 @@ struct mceusb_dev {
 	char name[128];
 	char phys[64];
 	enum mceusb_model_type model;
+
+	bool need_reset;	/* flag to issue a device resume cmd */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
@@ -736,6 +738,14 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
 
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
+	int rsize = sizeof(DEVICE_RESUME);
+
+	if (ir->need_reset) {
+		ir->need_reset = false;
+		mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX);
+		mdelay(10);
+	}
+
 	mce_request_packet(ir, data, size, MCEUSB_TX);
 	mdelay(10);
 }
@@ -912,6 +922,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 	case MCE_RSP_EQIRRXPORTEN:
 		ir->learning_enabled = ((hi & 0x02) == 0x02);
 		break;
+	case MCE_RSP_CMD_ILLEGAL:
+		ir->need_reset = true;
+		break;
 	default:
 		break;
 	}
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 5/9] [media] mceusb: query device for firmware emulator version
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (3 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Supposedly, there are essentially three different classes of devices
that are compatible with Microsoft's specs. First are the "legacy"
devices, which are built using Microsoft-provided hardware specs and
firmware. Second are "emulator" devices, which are built using custom
hardware and firmware, written to emulate Microsoft's firmware. Third
are "port" devices, which have their own device driver and firmware,
which provides compatible data to higher levels of the stack.

>From what I can tell, things like nuvoton-cir and fintek-cir are
essentially "port" devices -- their raw IR buffer format is very similar
to that of the mceusb devices. Now, within the mceusb driver, we have
three different "generations", which at first, seemed like maybe they
mapped to emulator versions. Unfortuantely, every single device I have
responds "illegal command" to the query to get firmware emulator version
from the hardware, which means they're either all emulator version 1, or
they're legacy devices, and our different "generations" aren't at all
related here. Though in theory, its possible the gen1 devices are
"legacy" devices and the rest are emulator v1. There are some useful
features of the v2 interface I was hoping to play with, but alas...

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index a777623..114fb13 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -439,12 +439,14 @@ struct mceusb_dev {
 	enum mceusb_model_type model;
 
 	bool need_reset;	/* flag to issue a device resume cmd */
+	u8 emver;		/* emulator interface version */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
 static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
 				   MCE_CMD_RESUME};
 static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
+static char GET_EMVER[]		= {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER};
 static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
@@ -916,6 +918,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 		break;
 
 	/* 1-byte return value commands */
+	case MCE_RSP_EQEMVER:
+		ir->emver = hi;
+		break;
 	case MCE_RSP_EQIRTXPORTS:
 		ir->tx_mask = hi;
 		break;
@@ -1038,6 +1043,13 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
+static void mceusb_get_emulator_version(struct mceusb_dev *ir)
+{
+	/* If we get no reply or an illegal command reply, its ver 1, says MS */
+	ir->emver = 1;
+	mce_async_out(ir, GET_EMVER, sizeof(GET_EMVER));
+}
+
 static void mceusb_gen1_init(struct mceusb_dev *ir)
 {
 	int ret;
@@ -1291,6 +1303,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 	mce_dbg(&intf->dev, "Flushing receive buffers\n");
 	mce_flush_rx_buffer(ir, maxp);
 
+	/* figure out which firmware/emulator version this hardware has */
+	mceusb_get_emulator_version(ir);
+
 	/* initialize device */
 	if (ir->flags.microsoft_gen1)
 		mceusb_gen1_init(ir);
@@ -1308,8 +1323,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 	device_set_wakeup_capable(ir->dev, true);
 	device_set_wakeup_enable(ir->dev, true);
 
-	dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
-		 dev->bus->busnum, dev->devnum);
+	dev_info(&intf->dev, "Registered %s with mce emulator interface "
+		 "version %x\n", name, ir->emver);
 
 	return 0;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 6/9] [media] mceusb: get misc port data from hardware
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (4 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

According to the specs, you can read the number of tx ports, number of
rx sensors, which tx ports have cables plugged into them, and which rx
sensors are active. In practice, most of my devices do seem to report
sane values for tx ports and rx sensors (but not all -- one without any
tx ports reports having them), and most report the active sensor
correctly, but only one of eight reports cabled tx ports correctly. So
for the most part, this is just for informational purposes.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   51 ++++++++++++++++++++++++++++++++++++++------
 1 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 114fb13..e4171f7 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -440,6 +440,10 @@ struct mceusb_dev {
 
 	bool need_reset;	/* flag to issue a device resume cmd */
 	u8 emver;		/* emulator interface version */
+	u8 num_txports;		/* number of transmit ports */
+	u8 num_rxports;		/* number of receive sensors */
+	u8 txports_cabled;	/* bitmask of transmitters with cable */
+	u8 rxports_active;	/* bitmask of active receive sensors */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
@@ -451,6 +455,7 @@ static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
 static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
+static char GET_NUM_PORTS[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRNUMPORTS};
 static char GET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS};
 static char GET_RX_SENSOR[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN};
 /* sub in desired values in lower byte or bytes for full command */
@@ -544,6 +549,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 
 	switch (cmd) {
 	case MCE_CMD_NULL:
+		if (subcmd == MCE_CMD_NULL)
+			break;
 		if ((subcmd == MCE_CMD_PORT_SYS) &&
 		    (data1 == MCE_CMD_RESUME))
 			dev_info(dev, "Device resume requested\n");
@@ -912,10 +919,20 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 	u8 lo = ir->buf_in[index + 2] & 0xff;
 
 	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;
+
 	/* 2-byte return value commands */
 	case MCE_RSP_EQIRTIMEOUT:
 		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;
+		break;
 
 	/* 1-byte return value commands */
 	case MCE_RSP_EQEMVER:
@@ -926,6 +943,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 		break;
 	case MCE_RSP_EQIRRXPORTEN:
 		ir->learning_enabled = ((hi & 0x02) == 0x02);
+		ir->rxports_active = hi;
 		break;
 	case MCE_RSP_CMD_ILLEGAL:
 		ir->need_reset = true;
@@ -1118,10 +1136,21 @@ static void mceusb_gen2_init(struct mceusb_dev *ir)
 
 static void mceusb_get_parameters(struct mceusb_dev *ir)
 {
+	int i;
+	unsigned char cmdbuf[3] = { MCE_CMD_PORT_SYS,
+				    MCE_CMD_GETPORTSTATUS, 0x00 };
+
+	/* defaults, if the hardware doesn't support querying */
+	ir->num_txports = 2;
+	ir->num_rxports = 2;
+
+	/* get number of tx and rx ports */
+	mce_async_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS));
+
 	/* get the carrier and frequency */
 	mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
 
-	if (!ir->flags.no_tx)
+	if (ir->num_txports && !ir->flags.no_tx)
 		/* get the transmitter bitmask */
 		mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
 
@@ -1130,6 +1159,11 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
 
 	/* get receiver sensor setting */
 	mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+
+	for (i = 0; i < ir->num_txports; i++) {
+		cmdbuf[2] = i;
+		mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+	}
 }
 
 static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
@@ -1161,11 +1195,6 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 	rc->driver_type = RC_DRIVER_IR_RAW;
 	rc->allowed_protos = RC_TYPE_ALL;
 	rc->timeout = MS_TO_NS(100);
-	if (!ir->flags.no_tx) {
-		rc->s_tx_mask = mceusb_set_tx_mask;
-		rc->s_tx_carrier = mceusb_set_tx_carrier;
-		rc->tx_ir = mceusb_tx_ir;
-	}
 	rc->driver_name = DRIVER_NAME;
 	rc->map_name = mceusb_model[ir->model].rc_map ?
 			mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
@@ -1314,8 +1343,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	mceusb_get_parameters(ir);
 
-	if (!ir->flags.no_tx)
+	if (ir->num_txports && !ir->flags.no_tx) {
+		ir->rc->s_tx_mask = mceusb_set_tx_mask;
+		ir->rc->s_tx_carrier = mceusb_set_tx_carrier;
+		ir->rc->tx_ir = mceusb_tx_ir;
 		mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
+	}
 
 	usb_set_intfdata(intf, ir);
 
@@ -1325,6 +1358,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	dev_info(&intf->dev, "Registered %s with mce emulator interface "
 		 "version %x\n", name, ir->emver);
+	dev_info(&intf->dev, "%x tx ports (0x%x cabled) and "
+		 "%x rx sensors (0x%x active)\n",
+		 ir->num_txports, ir->txports_cabled,
+		 ir->num_rxports, ir->rxports_active);
 
 	return 0;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (5 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index e4171f7..bbd79c0 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -452,6 +452,7 @@ static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
 static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
 static char GET_EMVER[]		= {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER};
 static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
+static char FLASH_LED[]		= {MCE_CMD_PORT_SYS, MCE_CMD_FLASHLED};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
 static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
@@ -592,6 +593,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 				dev_info(dev, "TX port %d: blaster is%s connected\n",
 					 data1 + 1, data4 ? " not" : "");
 			break;
+		case MCE_CMD_FLASHLED:
+			dev_info(dev, "Attempting to flash LED\n");
+			break;
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
@@ -1166,6 +1170,14 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
 	}
 }
 
+static void mceusb_flash_led(struct mceusb_dev *ir)
+{
+	if (ir->emver < 2)
+		return;
+
+	mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
+}
+
 static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 {
 	struct device *dev = ir->dev;
@@ -1343,6 +1355,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	mceusb_get_parameters(ir);
 
+	mceusb_flash_led(ir);
+
 	if (ir->num_txports && !ir->flags.no_tx) {
 		ir->rc->s_tx_mask = mceusb_set_tx_mask;
 		ir->rc->s_tx_carrier = mceusb_set_tx_carrier;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 8/9] [media] mceusb: report actual tx frequencies
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (6 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-14 22:09 ` [PATCH 9/9] [media] mceusb: update version, copyright, author Jarod Wilson
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Rather than dumping out hex values, lets print the actual calculated
frequency and period the hardware has been configured for. After this
change:

[ 2643.276215] mceusb 3-1:1.0: tx data: 9f 07 (length=2)
[ 2643.276218] mceusb 3-1:1.0: Get carrier mode and freq
[ 2643.277206] mceusb 3-1:1.0: rx data: 9f 06 01 42 (length=4)
[ 2643.277209] mceusb 3-1:1.0: Got carrier of 37037 Hz (period 27us)

Matches up perfectly with the table in Microsoft's docs.

Of course, I've noticed on one of my devices that the MS-recommended
default value of 1 for carrier pre-scaler and 66 for carrier period was
butchered, and instead of converting 66 to hex (0x42 like above), they
put in 0x66, so the hardware reports a default carrier of 24390Hz.
Fortunately, I guess, this particular device is rx-only, but I wouldn't
put it past other hw to screw up here too.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index bbd79c0..fa1d182 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -517,6 +517,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 	u8 cmd, subcmd, data1, data2, data3, data4, data5;
 	struct device *dev = ir->dev;
 	int i, start, skip = 0;
+	u32 carrier, period;
 
 	if (!debug)
 		return;
@@ -614,9 +615,14 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
 				 data1, data2);
 			break;
-		case MCE_CMD_SETIRCFS:
-			dev_info(dev, "%s carrier mode and freq of "
-				 "0x%02x 0x%02x\n", inout, data1, data2);
+		case MCE_RSP_EQIRCFS:
+			period = DIV_ROUND_CLOSEST(
+					(1 << data1 * 2) * (data2 + 1), 10);
+			if (!period)
+				break;
+			carrier = (1000 * 1000) / period;
+			dev_info(dev, "%s carrier of %u Hz (period %uus)\n",
+				 inout, carrier, period);
 			break;
 		case MCE_CMD_GETIRCFS:
 			dev_info(dev, "Get carrier mode and freq\n");
@@ -627,9 +633,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			break;
 		case MCE_RSP_EQIRTIMEOUT:
 			/* value is in units of 50us, so x*50/1000 ms */
+			period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000;
 			dev_info(dev, "%s receive timeout of %d ms\n",
-				 inout,
-				 ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000);
+				 inout, period);
 			break;
 		case MCE_CMD_GETIRTIMEOUT:
 			dev_info(dev, "Get receive timeout\n");
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 9/9] [media] mceusb: update version, copyright, author
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (7 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
@ 2011-07-14 22:09 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-14 22:09 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Add note about recent updates coming from Microsoft's publicly available
specs on Windows Media Center remotes and receivers/transmitters.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index fa1d182..053d079 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1,7 +1,7 @@
 /*
  * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
  *
- * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ * Copyright (c) 2010-2011, Jarod Wilson <jarod@redhat.com>
  *
  * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
  * Conti, Martin Blatter and Daniel Melander, the latter of which was
@@ -15,6 +15,11 @@
  * Jon Smirl, which included enhancements and simplifications to the
  * incoming IR buffer parsing routines.
  *
+ * Updated in July of 2011 with the aid of Microsoft's official
+ * remote/transceiver requirements and specification document, found at
+ * download.microsoft.com, title
+ * Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
+ *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,8 +46,8 @@
 #include <linux/delay.h>
 #include <media/rc-core.h>
 
-#define DRIVER_VERSION	"1.91"
-#define DRIVER_AUTHOR	"Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_VERSION	"1.92"
+#define DRIVER_AUTHOR	"Jarod Wilson <jarod@redhat.com>"
 #define DRIVER_DESC	"Windows Media Center Ed. eHome Infrared Transceiver " \
 			"device driver"
 #define DRIVER_NAME	"mceusb"
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds
  2011-07-14 22:09 ` [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
@ 2011-07-14 23:30   ` Mauro Carvalho Chehab
  2011-07-18 17:47     ` Jarod Wilson
  0 siblings, 1 reply; 23+ messages in thread
From: Mauro Carvalho Chehab @ 2011-07-14 23:30 UTC (permalink / raw)
  To: Jarod Wilson; +Cc: linux-media

Em 14-07-2011 19:09, Jarod Wilson escreveu:
> Sometimes the init routine is blasting commands out to the hardware
> faster than it can reply. Throw a brief delay in there to give the
> hardware a chance to reply before we send the next command.
> 
> Signed-off-by: Jarod Wilson <jarod@redhat.com>
> ---
>  drivers/media/rc/mceusb.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
> index 111bead..13a853b 100644
> --- a/drivers/media/rc/mceusb.c
> +++ b/drivers/media/rc/mceusb.c
> @@ -37,6 +37,7 @@
>  #include <linux/slab.h>
>  #include <linux/usb.h>
>  #include <linux/usb/input.h>
> +#include <linux/delay.h>
>  #include <media/rc-core.h>
>  
>  #define DRIVER_VERSION	"1.91"
> @@ -735,6 +736,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
>  static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
>  {
>  	mce_request_packet(ir, data, size, MCEUSB_TX);
> +	mdelay(10);

Can't it be a msleep() instead? Delays spend more power, and keeps the CPU busy while
running.

>  }
>  
>  static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds
  2011-07-14 23:30   ` Mauro Carvalho Chehab
@ 2011-07-18 17:47     ` Jarod Wilson
  2011-07-18 18:11       ` Jarod Wilson
  0 siblings, 1 reply; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 17:47 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Mauro Carvalho Chehab wrote:
> Em 14-07-2011 19:09, Jarod Wilson escreveu:
>> Sometimes the init routine is blasting commands out to the hardware
>> faster than it can reply. Throw a brief delay in there to give the
>> hardware a chance to reply before we send the next command.
>>
>> Signed-off-by: Jarod Wilson<jarod@redhat.com>
>> ---
>>   drivers/media/rc/mceusb.c |    2 ++
>>   1 files changed, 2 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
>> index 111bead..13a853b 100644
>> --- a/drivers/media/rc/mceusb.c
>> +++ b/drivers/media/rc/mceusb.c
>> @@ -37,6 +37,7 @@
>>   #include<linux/slab.h>
>>   #include<linux/usb.h>
>>   #include<linux/usb/input.h>
>> +#include<linux/delay.h>
>>   #include<media/rc-core.h>
>>
>>   #define DRIVER_VERSION	"1.91"
>> @@ -735,6 +736,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
>>   static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
>>   {
>>   	mce_request_packet(ir, data, size, MCEUSB_TX);
>> +	mdelay(10);
>
> Can't it be a msleep() instead? Delays spend more power, and keeps the CPU busy while
> running.

I think I was thinking we'd end up sleeping in an interrupt handler when 
we shouldn't be, but upon closer code inspection and actual testing, 
that's not the case, so yeah, those can be msleeps. While testing all 
code paths, I also discovered that patch 6 in the series breaks lirc tx 
support (the lirc dev is registered before the tx function pointers are 
filled in), so I'll resend at least patches 2 and 6...

-- 
Jarod Wilson
jarod@redhat.com



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds
  2011-07-18 17:47     ` Jarod Wilson
@ 2011-07-18 18:11       ` Jarod Wilson
  0 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 18:11 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Jarod Wilson wrote:
> Mauro Carvalho Chehab wrote:
>> Em 14-07-2011 19:09, Jarod Wilson escreveu:
>>> Sometimes the init routine is blasting commands out to the hardware
>>> faster than it can reply. Throw a brief delay in there to give the
>>> hardware a chance to reply before we send the next command.
>>>
>>> Signed-off-by: Jarod Wilson<jarod@redhat.com>
>>> ---
>>> drivers/media/rc/mceusb.c | 2 ++
>>> 1 files changed, 2 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
>>> index 111bead..13a853b 100644
>>> --- a/drivers/media/rc/mceusb.c
>>> +++ b/drivers/media/rc/mceusb.c
>>> @@ -37,6 +37,7 @@
>>> #include<linux/slab.h>
>>> #include<linux/usb.h>
>>> #include<linux/usb/input.h>
>>> +#include<linux/delay.h>
>>> #include<media/rc-core.h>
>>>
>>> #define DRIVER_VERSION "1.91"
>>> @@ -735,6 +736,7 @@ static void mce_request_packet(struct mceusb_dev
>>> *ir, unsigned char *data,
>>> static void mce_async_out(struct mceusb_dev *ir, unsigned char *data,
>>> int size)
>>> {
>>> mce_request_packet(ir, data, size, MCEUSB_TX);
>>> + mdelay(10);
>>
>> Can't it be a msleep() instead? Delays spend more power, and keeps the
>> CPU busy while
>> running.
>
> I think I was thinking we'd end up sleeping in an interrupt handler when
> we shouldn't be, but upon closer code inspection and actual testing,
> that's not the case, so yeah, those can be msleeps. While testing all
> code paths, I also discovered that patch 6 in the series breaks lirc tx
> support (the lirc dev is registered before the tx function pointers are
> filled in), so I'll resend at least patches 2 and 6...

I'll just resend an entire v2 series, the changes to patch 2 have 
cascading impact on multiple patches in the rest of the series.

-- 
Jarod Wilson
jarod@redhat.com



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 0/9] mceusb updates per MS docs
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (8 preceding siblings ...)
  2011-07-14 22:09 ` [PATCH 9/9] [media] mceusb: update version, copyright, author Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 1/9] [media] mceusb: command/response updates from " Jarod Wilson
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

This is a stack of updates made based on the Windows Media Center remote
and receiver/transmitter specification and requirements document that
Rafi Rubin recently pointed me at. Its titled
Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
which as of this writing, is publicly available from
download.microsoft.com.

Tested with 7 different mceusb devices, with no ill effects. Unfortunately,
for the most part, these chagnes don't actually improve any shortcomings in
the driver, but they do give us a better view of the hardware features and
whatnot, and a few things are better explained now, with most of the command
and response bits lining up with what MS has documented.

v2: use msleep instead of mdelay, and fix a tx regression in v1

Jarod Wilson (9):
  [media] mceusb: command/response updates from MS docs
  [media] mceusb: give hardware time to reply to cmds
  [media] mceusb: set wakeup bits for IR-based resume
  [media] mceusb: issue device resume cmd when needed
  [media] mceusb: query device for firmware emulator version
  [media] mceusb: get misc port data from hardware
  [media] mceusb: flash LED (emu v2+ only) to signal end of init
  [media] mceusb: report actual tx frequencies
  [media] mceusb: update version, copyright, author

 drivers/media/rc/mceusb.c |  410 +++++++++++++++++++++++++++++++--------------
 1 files changed, 280 insertions(+), 130 deletions(-)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 1/9] [media] mceusb: command/response updates from MS docs
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (9 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 0/9] mceusb updates per MS docs Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

I was recently pointed to the document titled
Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
which as of this writing, is publicly available from
download.microsoft.com. It covers a LOT of the gaps in the mceusb
driver, which to this point, was written almost entirely by
reverse-engineering. First up, I'm updating the defines for all the MCE
commands and responses to match their names in the spec. More to come...

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |  293 ++++++++++++++++++++++++++------------------
 1 files changed, 173 insertions(+), 120 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index ec972dc..111bead 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -63,43 +63,90 @@
 #define MCE_PULSE_MASK		0x7f /* Pulse mask */
 #define MCE_MAX_PULSE_LENGTH	0x7f /* Longest transmittable pulse symbol */
 
-#define MCE_HW_CMD_HEADER	0xff	/* MCE hardware command header */
-#define MCE_COMMAND_HEADER	0x9f	/* MCE command header */
-#define MCE_COMMAND_MASK	0xe0	/* Mask out command bits */
-#define MCE_COMMAND_NULL	0x00	/* These show up various places... */
-/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
- * then we're looking at a raw IR data sample */
-#define MCE_COMMAND_IRDATA	0x80
-#define MCE_PACKET_LENGTH_MASK	0x1f /* Packet length mask */
-
-/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+/*
+ * The interface between the host and the IR hardware is command-response
+ * based. All commands and responses have a consistent format, where a lead
+ * byte always identifies the type of data following it. The lead byte has
+ * a port value in the 3 highest bits and a length value in the 5 lowest
+ * bits.
+ *
+ * The length field is overloaded, with a value of 11111 indicating that the
+ * following byte is a command or response code, and the length of the entire
+ * message is determined by the code. If the length field is not 11111, then
+ * it specifies the number of bytes of port data that follow.
+ */
+#define MCE_CMD			0x1f
+#define MCE_PORT_IR		0x4	/* (0x4 << 5) | MCE_CMD = 0x9f */
+#define MCE_PORT_SYS		0x7	/* (0x7 << 5) | MCE_CMD = 0xff */
+#define MCE_PORT_SER		0x6	/* 0xc0 thru 0xdf flush & 0x1f bytes */
+#define MCE_PORT_MASK	0xe0	/* Mask out command bits */
+
+/* Command port headers */
+#define MCE_CMD_PORT_IR		0x9f	/* IR-related cmd/rsp */
+#define MCE_CMD_PORT_SYS	0xff	/* System (non-IR) device cmd/rsp */
+
+/* Commands that set device state  (2-4 bytes in length) */
+#define MCE_CMD_RESET		0xfe	/* Reset device, 2 bytes */
+#define MCE_CMD_RESUME		0xaa	/* Resume device after error, 2 bytes */
+#define MCE_CMD_SETIRCFS	0x06	/* Set tx carrier, 4 bytes */
+#define MCE_CMD_SETIRTIMEOUT	0x0c	/* Set timeout, 4 bytes */
+#define MCE_CMD_SETIRTXPORTS	0x08	/* Set tx ports, 3 bytes */
+#define MCE_CMD_SETIRRXPORTEN	0x14	/* Set rx ports, 3 bytes */
+#define MCE_CMD_FLASHLED	0x23	/* Flash receiver LED, 2 bytes */
+
+/* Commands that query device state (all 2 bytes, unless noted) */
+#define MCE_CMD_GETIRCFS	0x07	/* Get carrier */
+#define MCE_CMD_GETIRTIMEOUT	0x0d	/* Get timeout */
+#define MCE_CMD_GETIRTXPORTS	0x13	/* Get tx ports */
+#define MCE_CMD_GETIRRXPORTEN	0x15	/* Get rx ports */
+#define MCE_CMD_GETPORTSTATUS	0x11	/* Get tx port status, 3 bytes */
+#define MCE_CMD_GETIRNUMPORTS	0x16	/* Get number of ports */
+#define MCE_CMD_GETWAKESOURCE	0x17	/* Get wake source */
+#define MCE_CMD_GETEMVER	0x22	/* Get emulator interface version */
+#define MCE_CMD_GETDEVDETAILS	0x21	/* Get device details (em ver2 only) */
+#define MCE_CMD_GETWAKESUPPORT	0x20	/* Get wake details (em ver2 only) */
+#define MCE_CMD_GETWAKEVERSION	0x18	/* Get wake pattern (em ver2 only) */
+
+/* Misc commands */
+#define MCE_CMD_NOP		0xff	/* No operation */
+
+/* Responses to commands (non-error cases) */
+#define MCE_RSP_EQIRCFS		0x06	/* tx carrier, 4 bytes */
+#define MCE_RSP_EQIRTIMEOUT	0x0c	/* rx timeout, 4 bytes */
+#define MCE_RSP_GETWAKESOURCE	0x17	/* wake source, 3 bytes */
+#define MCE_RSP_EQIRTXPORTS	0x08	/* tx port mask, 3 bytes */
+#define MCE_RSP_EQIRRXPORTEN	0x14	/* rx port mask, 3 bytes */
+#define MCE_RSP_GETPORTSTATUS	0x11	/* tx port status, 7 bytes */
+#define MCE_RSP_EQIRRXCFCNT	0x15	/* rx carrier count, 4 bytes */
+#define MCE_RSP_EQIRNUMPORTS	0x16	/* number of ports, 4 bytes */
+#define MCE_RSP_EQWAKESUPPORT	0x20	/* wake capabilities, 3 bytes */
+#define MCE_RSP_EQWAKEVERSION	0x18	/* wake pattern details, 6 bytes */
+#define MCE_RSP_EQDEVDETAILS	0x21	/* device capabilities, 3 bytes */
+#define MCE_RSP_EQEMVER		0x22	/* emulator interface ver, 3 bytes */
+#define MCE_RSP_FLASHLED	0x23	/* success flashing LED, 2 bytes */
+
+/* Responses to error cases, must send MCE_CMD_RESUME to clear them */
+#define MCE_RSP_CMD_ILLEGAL	0xfe	/* illegal command for port, 2 bytes */
+#define MCE_RSP_TX_TIMEOUT	0x81	/* tx timed out, 2 bytes */
+
+/* Misc commands/responses not defined in the MCE remote/transceiver spec */
 #define MCE_CMD_SIG_END		0x01	/* End of signal */
 #define MCE_CMD_PING		0x03	/* Ping device */
 #define MCE_CMD_UNKNOWN		0x04	/* Unknown */
 #define MCE_CMD_UNKNOWN2	0x05	/* Unknown */
-#define MCE_CMD_S_CARRIER	0x06	/* Set TX carrier frequency */
-#define MCE_CMD_G_CARRIER	0x07	/* Get TX carrier frequency */
-#define MCE_CMD_S_TXMASK	0x08	/* Set TX port bitmask */
 #define MCE_CMD_UNKNOWN3	0x09	/* Unknown */
 #define MCE_CMD_UNKNOWN4	0x0a	/* Unknown */
 #define MCE_CMD_G_REVISION	0x0b	/* Get hw/sw revision */
-#define MCE_CMD_S_TIMEOUT	0x0c	/* Set RX timeout value */
-#define MCE_CMD_G_TIMEOUT	0x0d	/* Get RX timeout value */
 #define MCE_CMD_UNKNOWN5	0x0e	/* Unknown */
 #define MCE_CMD_UNKNOWN6	0x0f	/* Unknown */
-#define MCE_CMD_G_RXPORTSTS	0x11	/* Get RX port status */
-#define MCE_CMD_G_TXMASK	0x13	/* Set TX port bitmask */
-#define MCE_CMD_S_RXSENSOR	0x14	/* Set RX sensor (std/learning) */
-#define MCE_CMD_G_RXSENSOR	0x15	/* Get RX sensor (std/learning) */
-#define MCE_RSP_PULSE_COUNT	0x15	/* RX pulse count (only if learning) */
-#define MCE_CMD_TX_PORTS	0x16	/* Get number of TX ports */
-#define MCE_CMD_G_WAKESRC	0x17	/* Get wake source */
-#define MCE_CMD_UNKNOWN7	0x18	/* Unknown */
 #define MCE_CMD_UNKNOWN8	0x19	/* Unknown */
 #define MCE_CMD_UNKNOWN9	0x1b	/* Unknown */
-#define MCE_CMD_DEVICE_RESET	0xaa	/* Reset the hardware */
-#define MCE_RSP_CMD_INVALID	0xfe	/* Invalid command issued */
+#define MCE_CMD_NULL		0x00	/* These show up various places... */
 
+/* if buf[i] & MCE_PORT_MASK == 0x80 and buf[i] != MCE_CMD_PORT_IR,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA	0x80
+#define MCE_PACKET_LENGTH_MASK	0x1f /* Packet length mask */
 
 /* module parameters */
 #ifdef CONFIG_USB_DEBUG
@@ -390,46 +437,25 @@ struct mceusb_dev {
 	enum mceusb_model_type model;
 };
 
-/*
- * MCE Device Command Strings
- * Device command responses vary from device to device...
- * - DEVICE_RESET resets the hardware to its default state
- * - GET_REVISION fetches the hardware/software revision, common
- *   replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
- * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
- *   device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
- *   meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
- *   ((clk / frequency) - 1)
- * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
- *   response in the form of 9f 0c msb lsb
- * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
- *   the form of 9f 08 bm, where bm is the bitmask
- * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
- *   general use one or short-range learning one, in the form of
- *   9f 14 ss, where ss is either 01 for long-range or 02 for short
- * - SET_CARRIER_FREQ sets a new carrier mode and frequency
- * - SET_TX_BITMASK sets the transmitter bitmask
- * - SET_RX_TIMEOUT sets the receiver timeout
- * - SET_RX_SENSOR sets which receiver sensor to use
- */
-static char DEVICE_RESET[]	= {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
-				   MCE_CMD_DEVICE_RESET};
-static char GET_REVISION[]	= {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
-static char GET_UNKNOWN[]	= {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
-static char GET_UNKNOWN2[]	= {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
-static char GET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
-static char GET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
-static char GET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
-static char GET_RX_SENSOR[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
+/* MCE Device Command Strings, generally a port and command pair */
+static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
+				   MCE_CMD_RESUME};
+static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
+static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
+static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
+static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
+static char GET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS};
+static char GET_RX_SENSOR[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN};
 /* sub in desired values in lower byte or bytes for full command */
 /* FIXME: make use of these for transmit.
-static char SET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_CARRIER, 0x00, 0x00};
-static char SET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
-static char SET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_TIMEOUT, 0x00, 0x00};
-static char SET_RX_SENSOR[]	= {MCE_COMMAND_HEADER,
-				   MCE_CMD_S_RXSENSOR, 0x00};
+static char SET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR,
+				   MCE_CMD_SETIRCFS, 0x00, 0x00};
+static char SET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_SETIRTXPORTS, 0x00};
+static char SET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR,
+				   MCE_CMD_SETIRTIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[]	= {MCE_CMD_PORT_IR,
+				   MCE_RSP_EQIRRXPORTEN, 0x00};
 */
 
 static int mceusb_cmdsize(u8 cmd, u8 subcmd)
@@ -437,27 +463,33 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
 	int datasize = 0;
 
 	switch (cmd) {
-	case MCE_COMMAND_NULL:
-		if (subcmd == MCE_HW_CMD_HEADER)
+	case MCE_CMD_NULL:
+		if (subcmd == MCE_CMD_PORT_SYS)
 			datasize = 1;
 		break;
-	case MCE_HW_CMD_HEADER:
+	case MCE_CMD_PORT_SYS:
 		switch (subcmd) {
+		case MCE_RSP_EQWAKEVERSION:
+			datasize = 4;
+			break;
 		case MCE_CMD_G_REVISION:
 			datasize = 2;
 			break;
+		case MCE_RSP_EQWAKESUPPORT:
+			datasize = 1;
+			break;
 		}
-	case MCE_COMMAND_HEADER:
+	case MCE_CMD_PORT_IR:
 		switch (subcmd) {
 		case MCE_CMD_UNKNOWN:
-		case MCE_CMD_S_CARRIER:
-		case MCE_CMD_S_TIMEOUT:
-		case MCE_RSP_PULSE_COUNT:
+		case MCE_RSP_EQIRCFS:
+		case MCE_RSP_EQIRTIMEOUT:
+		case MCE_RSP_EQIRRXCFCNT:
 			datasize = 2;
 			break;
 		case MCE_CMD_SIG_END:
-		case MCE_CMD_S_TXMASK:
-		case MCE_CMD_S_RXSENSOR:
+		case MCE_RSP_EQIRTXPORTS:
+		case MCE_RSP_EQIRRXPORTEN:
 			datasize = 1;
 			break;
 		}
@@ -470,7 +502,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 {
 	char codes[USB_BUFLEN * 3 + 1];
 	char inout[9];
-	u8 cmd, subcmd, data1, data2;
+	u8 cmd, subcmd, data1, data2, data3, data4, data5;
 	struct device *dev = ir->dev;
 	int i, start, skip = 0;
 
@@ -500,18 +532,26 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 	subcmd = buf[start + 1] & 0xff;
 	data1  = buf[start + 2] & 0xff;
 	data2  = buf[start + 3] & 0xff;
+	data3  = buf[start + 4] & 0xff;
+	data4  = buf[start + 5] & 0xff;
+	data5  = buf[start + 6] & 0xff;
 
 	switch (cmd) {
-	case MCE_COMMAND_NULL:
-		if ((subcmd == MCE_HW_CMD_HEADER) &&
-		    (data1 == MCE_CMD_DEVICE_RESET))
-			dev_info(dev, "Device reset requested\n");
+	case MCE_CMD_NULL:
+		if ((subcmd == MCE_CMD_PORT_SYS) &&
+		    (data1 == MCE_CMD_RESUME))
+			dev_info(dev, "Device resume requested\n");
 		else
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 		break;
-	case MCE_HW_CMD_HEADER:
+	case MCE_CMD_PORT_SYS:
 		switch (subcmd) {
+		case MCE_RSP_EQEMVER:
+			if (!out)
+				dev_info(dev, "Emulator interface version %x\n",
+					 data1);
+			break;
 		case MCE_CMD_G_REVISION:
 			if (len == 2)
 				dev_info(dev, "Get hw/sw rev?\n");
@@ -520,21 +560,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 					 "0x%02x 0x%02x\n", data1, data2,
 					 buf[start + 4], buf[start + 5]);
 			break;
-		case MCE_CMD_DEVICE_RESET:
-			dev_info(dev, "Device reset requested\n");
+		case MCE_CMD_RESUME:
+			dev_info(dev, "Device resume requested\n");
+			break;
+		case MCE_RSP_CMD_ILLEGAL:
+			dev_info(dev, "Illegal PORT_SYS command\n");
+			break;
+		case MCE_RSP_EQWAKEVERSION:
+			if (!out)
+				dev_info(dev, "Wake version, proto: 0x%02x, "
+					 "payload: 0x%02x, address: 0x%02x, "
+					 "version: 0x%02x\n",
+					 data1, data2, data3, data4);
 			break;
-		case MCE_RSP_CMD_INVALID:
-			dev_info(dev, "Previous command not supported\n");
+		case MCE_RSP_GETPORTSTATUS:
+			if (!out)
+				/* We use data1 + 1 here, to match hw labels */
+				dev_info(dev, "TX port %d: blaster is%s connected\n",
+					 data1 + 1, data4 ? " not" : "");
 			break;
-		case MCE_CMD_UNKNOWN7:
-		case MCE_CMD_UNKNOWN9:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 			break;
 		}
 		break;
-	case MCE_COMMAND_HEADER:
+	case MCE_CMD_PORT_IR:
 		switch (subcmd) {
 		case MCE_CMD_SIG_END:
 			dev_info(dev, "End of signal\n");
@@ -546,47 +597,50 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
 				 data1, data2);
 			break;
-		case MCE_CMD_S_CARRIER:
+		case MCE_CMD_SETIRCFS:
 			dev_info(dev, "%s carrier mode and freq of "
 				 "0x%02x 0x%02x\n", inout, data1, data2);
 			break;
-		case MCE_CMD_G_CARRIER:
+		case MCE_CMD_GETIRCFS:
 			dev_info(dev, "Get carrier mode and freq\n");
 			break;
-		case MCE_CMD_S_TXMASK:
+		case MCE_RSP_EQIRTXPORTS:
 			dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
 				 inout, data1);
 			break;
-		case MCE_CMD_S_TIMEOUT:
+		case MCE_RSP_EQIRTIMEOUT:
 			/* value is in units of 50us, so x*50/1000 ms */
 			dev_info(dev, "%s receive timeout of %d ms\n",
 				 inout,
 				 ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000);
 			break;
-		case MCE_CMD_G_TIMEOUT:
+		case MCE_CMD_GETIRTIMEOUT:
 			dev_info(dev, "Get receive timeout\n");
 			break;
-		case MCE_CMD_G_TXMASK:
+		case MCE_CMD_GETIRTXPORTS:
 			dev_info(dev, "Get transmit blaster mask\n");
 			break;
-		case MCE_CMD_S_RXSENSOR:
+		case MCE_RSP_EQIRRXPORTEN:
 			dev_info(dev, "%s %s-range receive sensor in use\n",
 				 inout, data1 == 0x02 ? "short" : "long");
 			break;
-		case MCE_CMD_G_RXSENSOR:
-		/* aka MCE_RSP_PULSE_COUNT */
+		case MCE_CMD_GETIRRXPORTEN:
+		/* aka MCE_RSP_EQIRRXCFCNT */
 			if (out)
 				dev_info(dev, "Get receive sensor\n");
 			else if (ir->learning_enabled)
 				dev_info(dev, "RX pulse count: %d\n",
 					 ((data1 << 8) | data2));
 			break;
-		case MCE_RSP_CMD_INVALID:
-			dev_info(dev, "Error! Hardware is likely wedged...\n");
+		case MCE_RSP_EQIRNUMPORTS:
+			if (out)
+				break;
+			dev_info(dev, "Num TX ports: %x, num RX ports: %x\n",
+				 data1, data2);
+			break;
+		case MCE_RSP_CMD_ILLEGAL:
+			dev_info(dev, "Illegal PORT_IR command\n");
 			break;
-		case MCE_CMD_UNKNOWN2:
-		case MCE_CMD_UNKNOWN3:
-		case MCE_CMD_UNKNOWN5:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
@@ -599,8 +653,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 
 	if (cmd == MCE_IRDATA_TRAILER)
 		dev_info(dev, "End of raw IR data\n");
-	else if ((cmd != MCE_COMMAND_HEADER) &&
-		 ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+	else if ((cmd != MCE_CMD_PORT_IR) &&
+		 ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
 		dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
 }
 
@@ -616,9 +670,6 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
 	if (ir) {
 		len = urb->actual_length;
 
-		mce_dbg(ir->dev, "callback called (status=%d len=%d)\n",
-			urb->status, len);
-
 		mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
 	}
 
@@ -710,8 +761,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 		return -ENOMEM;
 
 	/* MCE tx init header */
-	cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
-	cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
+	cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
+	cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS;
 	cmdbuf[cmdcount++] = ir->tx_mask;
 
 	/* Generate mce packet data */
@@ -797,8 +848,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
 	struct mceusb_dev *ir = dev->priv;
 	int clk = 10000000;
 	int prescaler = 0, divisor = 0;
-	unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
-				    MCE_CMD_S_CARRIER, 0x00, 0x00 };
+	unsigned char cmdbuf[4] = { MCE_CMD_PORT_IR,
+				    MCE_CMD_SETIRCFS, 0x00, 0x00 };
 
 	/* Carrier has changed */
 	if (ir->carrier != carrier) {
@@ -847,16 +898,16 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 
 	switch (ir->buf_in[index]) {
 	/* 2-byte return value commands */
-	case MCE_CMD_S_TIMEOUT:
+	case MCE_RSP_EQIRTIMEOUT:
 		ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
 		break;
 
 	/* 1-byte return value commands */
-	case MCE_CMD_S_TXMASK:
+	case MCE_RSP_EQIRTXPORTS:
 		ir->tx_mask = hi;
 		break;
-	case MCE_CMD_S_RXSENSOR:
-		ir->learning_enabled = (hi == 0x02);
+	case MCE_RSP_EQIRRXPORTEN:
+		ir->learning_enabled = ((hi & 0x02) == 0x02);
 		break;
 	default:
 		break;
@@ -905,8 +956,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 			/* 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_COMMAND_HEADER) ||
-			    ((ir->cmd & MCE_COMMAND_MASK) !=
+			if ((ir->cmd == MCE_CMD_PORT_IR) ||
+			    ((ir->cmd & MCE_PORT_MASK) !=
 			     MCE_COMMAND_IRDATA)) {
 				ir->parser_state = SUBCMD;
 				continue;
@@ -1013,8 +1064,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 			      0x0000, 0x0100, NULL, 0, HZ * 3);
 	mce_dbg(dev, "%s - retC = %d\n", __func__, ret);
 
-	/* device reset */
-	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	/* device resume */
+	mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
 	/* get hw/sw revision? */
 	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
@@ -1024,14 +1075,16 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
 
 static void mceusb_gen2_init(struct mceusb_dev *ir)
 {
-	/* device reset */
-	mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+	/* device resume */
+	mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
 
 	/* get hw/sw revision? */
 	mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
 
-	/* unknown what the next two actually return... */
-	mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+	/* get wake version (protocol, key, address) */
+	mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION));
+
+	/* unknown what this one actually returns... */
 	mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
 }
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 2/9] [media] mceusb: give hardware time to reply to cmds
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (10 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 1/9] [media] mceusb: command/response updates from " Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Sometimes the init routine is blasting commands out to the hardware
faster than it can reply. Throw a brief delay in there to give the
hardware a chance to reply before we send the next command.

v2: use msleep instead of mdelay per Mauro's suggestion

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 111bead..b1ea485 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -735,6 +735,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
 	mce_request_packet(ir, data, size, MCEUSB_TX);
+	msleep(10);
 }
 
 static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 3/9] [media] mceusb: set wakeup bits for IR-based resume
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (11 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Its not uncommon for folks to force these bits enabled, because people
do want to wake their htpc kit via their remote. Lets just set the bits
for 'em.

v2: rebase for mdelay->msleep changes

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index b1ea485..ab074a3 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
+#include <linux/pm_wakeup.h>
 #include <media/rc-core.h>
 
 #define DRIVER_VERSION	"1.91"
@@ -1289,6 +1290,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	usb_set_intfdata(intf, ir);
 
+	/* enable wake via this device */
+	device_set_wakeup_capable(ir->dev, true);
+	device_set_wakeup_enable(ir->dev, true);
+
 	dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
 		 dev->bus->busnum, dev->devnum);
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 4/9] [media] mceusb: issue device resume cmd when needed
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (12 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

According to MS docs, the device firmware may halt after receiving an
unknown instruction, but that it should be possible to tell the firmware
to continue running by simply sending a device resume command. So lets
do that.

v2: use msleep instead of mdelay per Mauro's suggestion

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index ab074a3..f1fc11d 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -436,6 +436,8 @@ struct mceusb_dev {
 	char name[128];
 	char phys[64];
 	enum mceusb_model_type model;
+
+	bool need_reset;	/* flag to issue a device resume cmd */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
@@ -735,6 +737,14 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
 
 static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
 {
+	int rsize = sizeof(DEVICE_RESUME);
+
+	if (ir->need_reset) {
+		ir->need_reset = false;
+		mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX);
+		msleep(10);
+	}
+
 	mce_request_packet(ir, data, size, MCEUSB_TX);
 	msleep(10);
 }
@@ -911,6 +921,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 	case MCE_RSP_EQIRRXPORTEN:
 		ir->learning_enabled = ((hi & 0x02) == 0x02);
 		break;
+	case MCE_RSP_CMD_ILLEGAL:
+		ir->need_reset = true;
+		break;
 	default:
 		break;
 	}
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 5/9] [media] mceusb: query device for firmware emulator version
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (13 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Supposedly, there are essentially three different classes of devices
that are compatible with Microsoft's specs. First are the "legacy"
devices, which are built using Microsoft-provided hardware specs and
firmware. Second are "emulator" devices, which are built using custom
hardware and firmware, written to emulate Microsoft's firmware. Third
are "port" devices, which have their own device driver and firmware,
which provides compatible data to higher levels of the stack.

>From what I can tell, things like nuvoton-cir and fintek-cir are
essentially "port" devices -- their raw IR buffer format is very similar
to that of the mceusb devices. Now, within the mceusb driver, we have
three different "generations", which at first, seemed like maybe they
mapped to emulator versions. Unfortuantely, every single device I have
responds "illegal command" to the query to get firmware emulator version
from the hardware, which means they're either all emulator version 1, or
they're legacy devices, and our different "generations" aren't at all
related here. Though in theory, its possible the gen1 devices are
"legacy" devices and the rest are emulator v1. There are some useful
features of the v2 interface I was hoping to play with, but alas...

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index f1fc11d..fb2fa9d 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -438,12 +438,14 @@ struct mceusb_dev {
 	enum mceusb_model_type model;
 
 	bool need_reset;	/* flag to issue a device resume cmd */
+	u8 emver;		/* emulator interface version */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
 static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
 				   MCE_CMD_RESUME};
 static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
+static char GET_EMVER[]		= {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER};
 static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
@@ -915,6 +917,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 		break;
 
 	/* 1-byte return value commands */
+	case MCE_RSP_EQEMVER:
+		ir->emver = hi;
+		break;
 	case MCE_RSP_EQIRTXPORTS:
 		ir->tx_mask = hi;
 		break;
@@ -1037,6 +1042,13 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
+static void mceusb_get_emulator_version(struct mceusb_dev *ir)
+{
+	/* If we get no reply or an illegal command reply, its ver 1, says MS */
+	ir->emver = 1;
+	mce_async_out(ir, GET_EMVER, sizeof(GET_EMVER));
+}
+
 static void mceusb_gen1_init(struct mceusb_dev *ir)
 {
 	int ret;
@@ -1290,6 +1302,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 	mce_dbg(&intf->dev, "Flushing receive buffers\n");
 	mce_flush_rx_buffer(ir, maxp);
 
+	/* figure out which firmware/emulator version this hardware has */
+	mceusb_get_emulator_version(ir);
+
 	/* initialize device */
 	if (ir->flags.microsoft_gen1)
 		mceusb_gen1_init(ir);
@@ -1307,8 +1322,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 	device_set_wakeup_capable(ir->dev, true);
 	device_set_wakeup_enable(ir->dev, true);
 
-	dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
-		 dev->bus->busnum, dev->devnum);
+	dev_info(&intf->dev, "Registered %s with mce emulator interface "
+		 "version %x\n", name, ir->emver);
 
 	return 0;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 6/9] [media] mceusb: get misc port data from hardware
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (14 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

According to the specs, you can read the number of tx ports, number of
rx sensors, which tx ports have cables plugged into them, and which rx
sensors are active. In practice, most of my devices do seem to report
sane values for tx ports and rx sensors (but not all -- one without any
tx ports reports having them), and most report the active sensor
correctly, but only one of eight reports cabled tx ports correctly. So
for the most part, this is just for informational purposes.

v2: put tx function wiring back where it was to un-break lirc tx

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   40 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 39 insertions(+), 1 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index fb2fa9d..9e71aef 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -439,6 +439,10 @@ struct mceusb_dev {
 
 	bool need_reset;	/* flag to issue a device resume cmd */
 	u8 emver;		/* emulator interface version */
+	u8 num_txports;		/* number of transmit ports */
+	u8 num_rxports;		/* number of receive sensors */
+	u8 txports_cabled;	/* bitmask of transmitters with cable */
+	u8 rxports_active;	/* bitmask of active receive sensors */
 };
 
 /* MCE Device Command Strings, generally a port and command pair */
@@ -450,6 +454,7 @@ static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
 static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
+static char GET_NUM_PORTS[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRNUMPORTS};
 static char GET_TX_BITMASK[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS};
 static char GET_RX_SENSOR[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN};
 /* sub in desired values in lower byte or bytes for full command */
@@ -543,6 +548,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 
 	switch (cmd) {
 	case MCE_CMD_NULL:
+		if (subcmd == MCE_CMD_NULL)
+			break;
 		if ((subcmd == MCE_CMD_PORT_SYS) &&
 		    (data1 == MCE_CMD_RESUME))
 			dev_info(dev, "Device resume requested\n");
@@ -911,10 +918,20 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 	u8 lo = ir->buf_in[index + 2] & 0xff;
 
 	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;
+
 	/* 2-byte return value commands */
 	case MCE_RSP_EQIRTIMEOUT:
 		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;
+		break;
 
 	/* 1-byte return value commands */
 	case MCE_RSP_EQEMVER:
@@ -925,6 +942,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
 		break;
 	case MCE_RSP_EQIRRXPORTEN:
 		ir->learning_enabled = ((hi & 0x02) == 0x02);
+		ir->rxports_active = hi;
 		break;
 	case MCE_RSP_CMD_ILLEGAL:
 		ir->need_reset = true;
@@ -1117,10 +1135,21 @@ static void mceusb_gen2_init(struct mceusb_dev *ir)
 
 static void mceusb_get_parameters(struct mceusb_dev *ir)
 {
+	int i;
+	unsigned char cmdbuf[3] = { MCE_CMD_PORT_SYS,
+				    MCE_CMD_GETPORTSTATUS, 0x00 };
+
+	/* defaults, if the hardware doesn't support querying */
+	ir->num_txports = 2;
+	ir->num_rxports = 2;
+
+	/* get number of tx and rx ports */
+	mce_async_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS));
+
 	/* get the carrier and frequency */
 	mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
 
-	if (!ir->flags.no_tx)
+	if (ir->num_txports && !ir->flags.no_tx)
 		/* get the transmitter bitmask */
 		mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
 
@@ -1129,6 +1158,11 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
 
 	/* get receiver sensor setting */
 	mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+
+	for (i = 0; i < ir->num_txports; i++) {
+		cmdbuf[2] = i;
+		mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+	}
 }
 
 static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
@@ -1324,6 +1358,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	dev_info(&intf->dev, "Registered %s with mce emulator interface "
 		 "version %x\n", name, ir->emver);
+	dev_info(&intf->dev, "%x tx ports (0x%x cabled) and "
+		 "%x rx sensors (0x%x active)\n",
+		 ir->num_txports, ir->txports_cabled,
+		 ir->num_rxports, ir->rxports_active);
 
 	return 0;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (15 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 9/9] [media] mceusb: update version, copyright, author Jarod Wilson
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

v2: rebase for mdelay->msleep changes and tx fix

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 9e71aef..160409e 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -451,6 +451,7 @@ static char DEVICE_RESUME[]	= {MCE_CMD_NULL, MCE_CMD_PORT_SYS,
 static char GET_REVISION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION};
 static char GET_EMVER[]		= {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER};
 static char GET_WAKEVERSION[]	= {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION};
+static char FLASH_LED[]		= {MCE_CMD_PORT_SYS, MCE_CMD_FLASHLED};
 static char GET_UNKNOWN2[]	= {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2};
 static char GET_CARRIER_FREQ[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS};
 static char GET_RX_TIMEOUT[]	= {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT};
@@ -591,6 +592,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 				dev_info(dev, "TX port %d: blaster is%s connected\n",
 					 data1 + 1, data4 ? " not" : "");
 			break;
+		case MCE_CMD_FLASHLED:
+			dev_info(dev, "Attempting to flash LED\n");
+			break;
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
@@ -1165,6 +1169,14 @@ static void mceusb_get_parameters(struct mceusb_dev *ir)
 	}
 }
 
+static void mceusb_flash_led(struct mceusb_dev *ir)
+{
+	if (ir->emver < 2)
+		return;
+
+	mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
+}
+
 static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 {
 	struct device *dev = ir->dev;
@@ -1347,6 +1359,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
 
 	mceusb_get_parameters(ir);
 
+	mceusb_flash_led(ir);
+
 	if (!ir->flags.no_tx)
 		mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 8/9] [media] mceusb: report actual tx frequencies
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (16 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  2011-07-18 19:54 ` [PATCH v2 9/9] [media] mceusb: update version, copyright, author Jarod Wilson
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Rather than dumping out hex values, lets print the actual calculated
frequency and period the hardware has been configured for. After this
change:

[ 2643.276215] mceusb 3-1:1.0: tx data: 9f 07 (length=2)
[ 2643.276218] mceusb 3-1:1.0: Get carrier mode and freq
[ 2643.277206] mceusb 3-1:1.0: rx data: 9f 06 01 42 (length=4)
[ 2643.277209] mceusb 3-1:1.0: Got carrier of 37037 Hz (period 27us)

Matches up perfectly with the table in Microsoft's docs.

Of course, I've noticed on one of my devices that the MS-recommended
default value of 1 for carrier pre-scaler and 66 for carrier period was
butchered, and instead of converting 66 to hex (0x42 like above), they
put in 0x66, so the hardware reports a default carrier of 24390Hz.
Fortunately, I guess, this particular device is rx-only, but I wouldn't
put it past other hw to screw up here too.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 160409e..b0c8bd2 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -516,6 +516,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 	u8 cmd, subcmd, data1, data2, data3, data4, data5;
 	struct device *dev = ir->dev;
 	int i, start, skip = 0;
+	u32 carrier, period;
 
 	if (!debug)
 		return;
@@ -613,9 +614,14 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
 				 data1, data2);
 			break;
-		case MCE_CMD_SETIRCFS:
-			dev_info(dev, "%s carrier mode and freq of "
-				 "0x%02x 0x%02x\n", inout, data1, data2);
+		case MCE_RSP_EQIRCFS:
+			period = DIV_ROUND_CLOSEST(
+					(1 << data1 * 2) * (data2 + 1), 10);
+			if (!period)
+				break;
+			carrier = (1000 * 1000) / period;
+			dev_info(dev, "%s carrier of %u Hz (period %uus)\n",
+				 inout, carrier, period);
 			break;
 		case MCE_CMD_GETIRCFS:
 			dev_info(dev, "Get carrier mode and freq\n");
@@ -626,9 +632,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
 			break;
 		case MCE_RSP_EQIRTIMEOUT:
 			/* value is in units of 50us, so x*50/1000 ms */
+			period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000;
 			dev_info(dev, "%s receive timeout of %d ms\n",
-				 inout,
-				 ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000);
+				 inout, period);
 			break;
 		case MCE_CMD_GETIRTIMEOUT:
 			dev_info(dev, "Get receive timeout\n");
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 9/9] [media] mceusb: update version, copyright, author
  2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
                   ` (17 preceding siblings ...)
  2011-07-18 19:54 ` [PATCH v2 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
@ 2011-07-18 19:54 ` Jarod Wilson
  18 siblings, 0 replies; 23+ messages in thread
From: Jarod Wilson @ 2011-07-18 19:54 UTC (permalink / raw)
  To: linux-media; +Cc: Jarod Wilson

Add note about recent updates coming from Microsoft's publicly available
specs on Windows Media Center remotes and receivers/transmitters.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/media/rc/mceusb.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index b0c8bd2..c4a41f1 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1,7 +1,7 @@
 /*
  * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
  *
- * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ * Copyright (c) 2010-2011, Jarod Wilson <jarod@redhat.com>
  *
  * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
  * Conti, Martin Blatter and Daniel Melander, the latter of which was
@@ -15,6 +15,11 @@
  * Jon Smirl, which included enhancements and simplifications to the
  * incoming IR buffer parsing routines.
  *
+ * Updated in July of 2011 with the aid of Microsoft's official
+ * remote/transceiver requirements and specification document, found at
+ * download.microsoft.com, title
+ * Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf
+ *
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,8 +45,8 @@
 #include <linux/pm_wakeup.h>
 #include <media/rc-core.h>
 
-#define DRIVER_VERSION	"1.91"
-#define DRIVER_AUTHOR	"Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_VERSION	"1.92"
+#define DRIVER_AUTHOR	"Jarod Wilson <jarod@redhat.com>"
 #define DRIVER_DESC	"Windows Media Center Ed. eHome Infrared Transceiver " \
 			"device driver"
 #define DRIVER_NAME	"mceusb"
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2011-07-18 19:55 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-14 22:09 [PATCH 0/9] mceusb updates per MS docs Jarod Wilson
2011-07-14 22:09 ` [PATCH 1/9] [media] mceusb: command/response updates from " Jarod Wilson
2011-07-14 22:09 ` [PATCH 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
2011-07-14 23:30   ` Mauro Carvalho Chehab
2011-07-18 17:47     ` Jarod Wilson
2011-07-18 18:11       ` Jarod Wilson
2011-07-14 22:09 ` [PATCH 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
2011-07-14 22:09 ` [PATCH 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
2011-07-14 22:09 ` [PATCH 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
2011-07-14 22:09 ` [PATCH 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
2011-07-14 22:09 ` [PATCH 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
2011-07-14 22:09 ` [PATCH 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
2011-07-14 22:09 ` [PATCH 9/9] [media] mceusb: update version, copyright, author Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 0/9] mceusb updates per MS docs Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 1/9] [media] mceusb: command/response updates from " Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 2/9] [media] mceusb: give hardware time to reply to cmds Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 3/9] [media] mceusb: set wakeup bits for IR-based resume Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 4/9] [media] mceusb: issue device resume cmd when needed Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 5/9] [media] mceusb: query device for firmware emulator version Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 6/9] [media] mceusb: get misc port data from hardware Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 7/9] [media] mceusb: flash LED (emu v2+ only) to signal end of init Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 8/9] [media] mceusb: report actual tx frequencies Jarod Wilson
2011-07-18 19:54 ` [PATCH v2 9/9] [media] mceusb: update version, copyright, author Jarod Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).