From b05681b91709a19b40a452f566cc852619b30082 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Jul 2011 02:23:20 -0300 Subject: [media] rc-main: Fix device de-registration logic rc unregister logic were deadly broken, preventing some drivers to be removed. Among the broken things, rc_dev_uevent() is being called during device_del(), causing a data filling on an area that it is not ready anymore. Also, some drivers have a stop callback defined, that needs to be called before data removal, as it stops data polling. Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 51a23f48bc7d..666d4bb5b1fb 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -928,10 +928,6 @@ out: static void rc_dev_release(struct device *device) { - struct rc_dev *dev = to_rc_dev(device); - - kfree(dev); - module_put(THIS_MODULE); } #define ADD_HOTPLUG_VAR(fmt, val...) \ @@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); + if (!dev || !dev->input_dev) + return -ENODEV; + if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) @@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device); void rc_free_device(struct rc_dev *dev) { - if (dev) { + if (!dev) + return; + + if (dev->input_dev) input_free_device(dev->input_dev); - put_device(&dev->dev); - } + + put_device(&dev->dev); + + kfree(dev); + module_put(THIS_MODULE); } EXPORT_SYMBOL_GPL(rc_free_device); @@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev) if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + /* Freeing the table should also call the stop callback */ + ir_free_table(&dev->rc_map); + IR_dprintk(1, "Freed keycode table\n"); + input_unregister_device(dev->input_dev); dev->input_dev = NULL; - ir_free_table(&dev->rc_map); - IR_dprintk(1, "Freed keycode table\n"); + device_del(&dev->dev); - device_unregister(&dev->dev); + rc_free_device(dev); } + EXPORT_SYMBOL_GPL(rc_unregister_device); /* -- cgit From 47a09b082f70502195ee800bb0cd6f311b125c8f Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 14:20:46 -0300 Subject: [media] imon: rate-limit send_packet spew There are folks with flaky imon hardware out there that doesn't always respond to requests to write to their displays for some reason, which can flood logs quickly when something like lcdproc is trying to constantly update the display, so lets rate-limit all that error spew. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 6bc35eeb653b..caa3e3ac41cb 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -516,19 +517,19 @@ static int send_packet(struct imon_context *ictx) if (retval) { ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ - pr_err("error submitting urb(%d)\n", retval); + pr_err_ratelimited("error submitting urb(%d)\n", retval); } else { /* Wait for transmission to complete (or abort) */ mutex_unlock(&ictx->lock); retval = wait_for_completion_interruptible( &ictx->tx.finished); if (retval) - pr_err("task interrupted\n"); + pr_err_ratelimited("task interrupted\n"); mutex_lock(&ictx->lock); retval = ictx->tx.status; if (retval) - pr_err("packet tx failed (%d)\n", retval); + pr_err_ratelimited("packet tx failed (%d)\n", retval); } kfree(control_req); @@ -830,20 +831,20 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->dev_present_intf0) { - pr_err("no iMON device present\n"); + pr_err_ratelimited("no iMON device present\n"); retval = -ENODEV; goto exit; } if (n_bytes <= 0 || n_bytes > 32) { - pr_err("invalid payload size\n"); + pr_err_ratelimited("invalid payload size\n"); retval = -EINVAL; goto exit; } @@ -869,7 +870,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); goto exit; } else { seq += 2; @@ -883,7 +884,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx->usb_tx_buf[7] = (unsigned char) seq; retval = send_packet(ictx); if (retval) - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); exit: mutex_unlock(&ictx->lock); @@ -912,20 +913,21 @@ static ssize_t lcd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->display_supported) { - pr_err("no iMON display present\n"); + pr_err_ratelimited("no iMON display present\n"); retval = -ENODEV; goto exit; } if (n_bytes != 8) { - pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); + pr_err_ratelimited("invalid payload size: %d (expected 8)\n", + (int)n_bytes); retval = -EINVAL; goto exit; } @@ -937,7 +939,7 @@ static ssize_t lcd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed!\n"); + pr_err_ratelimited("send packet failed!\n"); goto exit; } else { dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -- cgit From a6fbd3b77ad0ad7b3020b4f50659e740ff68c719 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:21 -0300 Subject: [media] mceusb: command/response updates from MS docs 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 293 +++++++++++++++++++++++++++------------------- 1 file changed, 173 insertions(+), 120 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 85ff9a1ffb39..eee28a57e2b4 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); } @@ -708,8 +759,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) 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 */ @@ -795,8 +846,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) { @@ -845,16 +896,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; @@ -903,8 +954,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; @@ -1011,8 +1062,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)); @@ -1022,14 +1073,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)); } -- cgit From 417c0a23b7d0384682d6032fbc6a62ab25ce7c18 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:22 -0300 Subject: [media] mceusb: give hardware time to reply to cmds 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index eee28a57e2b4..7af57383c89d 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) -- cgit From fa3348980a504c01e300823ab743cb2d874327fa Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:23 -0300 Subject: [media] mceusb: set wakeup bits for IR-based resume 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 7af57383c89d..d095b4d13d79 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #define DRIVER_VERSION "1.91" @@ -1287,6 +1288,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); -- cgit From 4840b788ad608977d47964d39ee53a55bec41702 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:24 -0300 Subject: [media] mceusb: issue device resume cmd when needed 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index d095b4d13d79..181a9b61de0e 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); } @@ -909,6 +919,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; } -- cgit From ab1072eba9a635511279c72150b35c1cf95ceda1 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:25 -0300 Subject: [media] mceusb: query device for firmware emulator version 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 181a9b61de0e..4c5909f06ac2 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}; @@ -913,6 +915,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; @@ -1035,6 +1040,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; @@ -1288,6 +1300,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); @@ -1305,8 +1320,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; -- cgit From a411e83944bc48ce274b1bafdb6929846815856c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:26 -0300 Subject: [media] mceusb: get misc port data from hardware 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 4c5909f06ac2..c4f3bc00611d 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"); @@ -909,10 +916,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: @@ -923,6 +940,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; @@ -1115,10 +1133,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)); @@ -1127,6 +1156,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) @@ -1322,6 +1356,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; -- cgit From b71969bee23ea0c44c594e5027ba26029d27afea Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:27 -0300 Subject: [media] mceusb: flash LED (emu v2+ only) to signal end of init Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index c4f3bc00611d..8fa5a725bed7 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); @@ -1163,6 +1167,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; @@ -1345,6 +1357,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); -- cgit From e217fb43c47830857a685673ae0dc3e28493bb88 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:28 -0300 Subject: [media] mceusb: report actual tx frequencies Rather than dumping out hex values, lets print the actual calculated frequency and period the hardware has been configured for. After this [ 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 8fa5a725bed7..e51637f46ab2 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"); -- cgit From fda516b72afcddbb617c75c93fe6316e4356a14b Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:29 -0300 Subject: [media] mceusb: update version, copyright, author 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index e51637f46ab2..60d3c1e09712 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 + * Copyright (c) 2010-2011, Jarod Wilson * * 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 #include -#define DRIVER_VERSION "1.91" -#define DRIVER_AUTHOR "Jarod Wilson " +#define DRIVER_VERSION "1.92" +#define DRIVER_AUTHOR "Jarod Wilson " #define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ "device driver" #define DRIVER_NAME "mceusb" -- cgit From 2f00e158b59bf83b8e6bc84130ac291a28827e76 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 19:04:49 -0300 Subject: [media] redrat3: remove unused dev struct members Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index a16604477917..61287fcca61a 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -195,11 +195,6 @@ struct redrat3_dev { dma_addr_t dma_in; dma_addr_t dma_out; - /* true if write urb is busy */ - bool write_busy; - /* wait for the write to finish */ - struct completion write_finished; - /* locks this structure */ struct mutex lock; @@ -207,8 +202,6 @@ struct redrat3_dev { struct timer_list rx_timeout; u32 hw_timeout; - /* Is the device currently receiving? */ - bool recv_in_progress; /* is the detector enabled*/ bool det_enabled; /* Is the device currently transmitting?*/ -- cgit From 63f409a444fa295247363a28381314683d6f4596 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 14 Aug 2011 09:18:46 -0300 Subject: [media] Add missing OK key to PCTV IR keymap Hi, The following patch adds the IR code for the missing "OK" key to the Pinnacle PCTV HD map. This map is now used by the PCTV 290e DVB-T2 device, whose remote control has 26 buttons. Signed-off-by: Chris Rankin Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 8d558ae63456..31fc64cd17ba 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -20,6 +20,7 @@ static struct rc_map_table pinnacle_pctv_hd[] = { { 0x0701, KEY_MENU }, /* Pinnacle logo */ { 0x0739, KEY_POWER }, { 0x0703, KEY_VOLUMEUP }, + { 0x0705, KEY_OK }, { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, -- cgit From 7de3461c93a6d65355113cca333723eb8a1a0225 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:46 -0300 Subject: [media] ene_ir: Use current logging styles Add pr_fmt. Convert ene_warn and ene_notice to pr_. Use pr_debug in __dbg macro and a little neatening. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 73 ++++++++++++++++++++++++----------------------- drivers/media/rc/ene_ir.h | 19 ++++-------- 2 files changed, 42 insertions(+), 50 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 2b9c2569d74a..cf10ecf5acec 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -30,6 +30,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -118,31 +120,31 @@ static int ene_hw_detect(struct ene_device *dev) dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4; if (hw_revision == 0xFF) { - ene_warn("device seems to be disabled"); - ene_warn("send a mail to lirc-list@lists.sourceforge.net"); - ene_warn("please attach output of acpidump and dmidecode"); + pr_warn("device seems to be disabled\n"); + pr_warn("send a mail to lirc-list@lists.sourceforge.net\n"); + pr_warn("please attach output of acpidump and dmidecode\n"); return -ENODEV; } - ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x", - chip_major, chip_minor, old_ver, hw_revision); + pr_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n", + chip_major, chip_minor, old_ver, hw_revision); - ene_notice("PLL freq = %d", dev->pll_freq); + pr_notice("PLL freq = %d\n", dev->pll_freq); if (chip_major == 0x33) { - ene_warn("chips 0x33xx aren't supported"); + pr_warn("chips 0x33xx aren't supported\n"); return -ENODEV; } if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { dev->hw_revision = ENE_HW_C; - ene_notice("KB3926C detected"); + pr_notice("KB3926C detected\n"); } else if (old_ver == 0x24 && hw_revision == 0xC0) { dev->hw_revision = ENE_HW_B; - ene_notice("KB3926B detected"); + pr_notice("KB3926B detected\n"); } else { dev->hw_revision = ENE_HW_D; - ene_notice("KB3926D or higher detected"); + pr_notice("KB3926D or higher detected\n"); } /* detect features hardware supports */ @@ -152,7 +154,7 @@ static int ene_hw_detect(struct ene_device *dev) fw_reg1 = ene_read_reg(dev, ENE_FW1); fw_reg2 = ene_read_reg(dev, ENE_FW2); - ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2); + pr_notice("Firmware regs: %02x %02x\n", fw_reg1, fw_reg2); dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A); dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING); @@ -161,30 +163,29 @@ static int ene_hw_detect(struct ene_device *dev) if (dev->hw_learning_and_tx_capable) dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT); - ene_notice("Hardware features:"); + pr_notice("Hardware features:\n"); if (dev->hw_learning_and_tx_capable) { - ene_notice("* Supports transmitting & learning mode"); - ene_notice(" This feature is rare and therefore,"); - ene_notice(" you are welcome to test it,"); - ene_notice(" and/or contact the author via:"); - ene_notice(" lirc-list@lists.sourceforge.net"); - ene_notice(" or maximlevitsky@gmail.com"); + pr_notice("* Supports transmitting & learning mode\n"); + pr_notice(" This feature is rare and therefore,\n"); + pr_notice(" you are welcome to test it,\n"); + pr_notice(" and/or contact the author via:\n"); + pr_notice(" lirc-list@lists.sourceforge.net\n"); + pr_notice(" or maximlevitsky@gmail.com\n"); - ene_notice("* Uses GPIO %s for IR raw input", - dev->hw_use_gpio_0a ? "40" : "0A"); + pr_notice("* Uses GPIO %s for IR raw input\n", + dev->hw_use_gpio_0a ? "40" : "0A"); if (dev->hw_fan_input) - ene_notice("* Uses unused fan feedback input as source" - " of demodulated IR data"); + pr_notice("* Uses unused fan feedback input as source of demodulated IR data\n"); } if (!dev->hw_fan_input) - ene_notice("* Uses GPIO %s for IR demodulated input", - dev->hw_use_gpio_0a ? "0A" : "40"); + pr_notice("* Uses GPIO %s for IR demodulated input\n", + dev->hw_use_gpio_0a ? "0A" : "40"); if (dev->hw_extra_buffer) - ene_notice("* Uses new style input buffer"); + pr_notice("* Uses new style input buffer\n"); return 0; } @@ -215,13 +216,13 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev) dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8; - ene_notice("Hardware uses 2 extended buffers:"); - ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address, - dev->extra_buf1_len); - ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address, - dev->extra_buf2_len); + pr_notice("Hardware uses 2 extended buffers:\n"); + pr_notice(" 0x%04x - len : %d\n", + dev->extra_buf1_address, dev->extra_buf1_len); + pr_notice(" 0x%04x - len : %d\n", + dev->extra_buf2_address, dev->extra_buf2_len); - ene_notice("Total buffer len = %d", dev->buffer_len); + pr_notice("Total buffer len = %d\n", dev->buffer_len); if (dev->buffer_len > 64 || dev->buffer_len < 16) goto error; @@ -240,7 +241,7 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev) ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); return; error: - ene_warn("Error validating extra buffers, device probably won't work"); + pr_warn("Error validating extra buffers, device probably won't work\n"); dev->hw_extra_buffer = false; ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); } @@ -588,7 +589,7 @@ static void ene_tx_enable(struct ene_device *dev) dbg("TX: Transmitter #2 is connected"); if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN))) - ene_warn("TX: transmitter cable isn't connected!"); + pr_warn("TX: transmitter cable isn't connected!\n"); /* disable receive on revc */ if (dev->hw_revision == ENE_HW_C) @@ -615,7 +616,7 @@ static void ene_tx_sample(struct ene_device *dev) bool pulse = dev->tx_sample_pulse; if (!dev->tx_buffer) { - ene_warn("TX: BUG: attempt to transmit NULL buffer"); + pr_warn("TX: BUG: attempt to transmit NULL buffer\n"); return; } @@ -1049,7 +1050,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) dev->hw_learning_and_tx_capable = true; setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, (long unsigned int)dev); - ene_warn("Simulation of TX activated"); + pr_warn("Simulation of TX activated\n"); } if (!dev->hw_learning_and_tx_capable) @@ -1089,7 +1090,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (error < 0) goto error; - ene_notice("driver has been successfully loaded"); + pr_notice("driver has been successfully loaded\n"); return 0; error: if (dev && dev->irq >= 0) diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index 017c209cdf8a..fd108d90f750 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -182,20 +182,11 @@ #define ENE_HW_C 2 /* 3926C */ #define ENE_HW_D 3 /* 3926D or later */ -#define ene_printk(level, text, ...) \ - printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__) - -#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__) -#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__) - - -#define __dbg(level, format, ...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG ENE_DRIVER_NAME \ - ": " format "\n", ## __VA_ARGS__); \ - } while (0) - +#define __dbg(level, format, ...) \ +do { \ + if (debug >= level) \ + pr_debug(format "\n", ## __VA_ARGS__); \ +} while (0) #define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) #define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) -- cgit From d8a10ac948545d8a4261728719af39b5dffaf7da Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:47 -0300 Subject: [media] winbond-cir: Use current logging styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add pr_fmt, convert printks to pr_. Signed-off-by: Joe Perches Acked-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index bec8abc965f7..13f54b51194a 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -41,6 +41,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1155,12 +1157,12 @@ wbcir_init(void) case IR_PROTOCOL_RC6: break; default: - printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n"); + pr_err("Invalid power-on protocol\n"); } ret = pnp_register_driver(&wbcir_driver); if (ret) - printk(KERN_ERR DRVNAME ": Unable to register driver\n"); + pr_err("Unable to register driver\n"); return ret; } -- cgit From 6f6b90c9231ad6b18f7393e1b6c6cef9dc6aa77c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 19 Jul 2011 12:12:47 -0300 Subject: [media] imon: don't parse scancodes until intf configured The imon devices have either 1 or 2 usb interfaces on them, each wired up to its own urb callback. The interface 0 urb callback is wired up before the imon context's rc_dev pointer is filled in, which is necessary for imon 0xffdc device auto-detection to work properly, but we need to make sure we don't actually run the callback routines until we've entirely filled in the necessary bits for each given interface, lest we wind up oopsing. Technically, any imon device could have hit this, but the issue is exacerbated on the 0xffdc devices, which send a constant stream of interrupts, even when they have no valid key data. CC: Andy Walls CC: Chris W Reported-by: Chris W Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index caa3e3ac41cb..6ed96465137a 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1658,7 +1658,7 @@ static void usb_rx_callback_intf0(struct urb *urb) return; ictx = (struct imon_context *)urb->context; - if (!ictx) + if (!ictx || !ictx->dev_present_intf0) return; switch (urb->status) { @@ -1690,7 +1690,7 @@ static void usb_rx_callback_intf1(struct urb *urb) return; ictx = (struct imon_context *)urb->context; - if (!ictx) + if (!ictx || !ictx->dev_present_intf1) return; switch (urb->status) { @@ -2118,7 +2118,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev = dev; ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; ictx->rf_device = false; @@ -2157,6 +2156,8 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto rdev_setup_failed; } + ictx->dev_present_intf0 = true; + mutex_unlock(&ictx->lock); return ictx; @@ -2200,7 +2201,6 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf1 = true; ictx->rx_urb_intf1 = rx_urb; ret = -ENODEV; @@ -2229,6 +2229,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, goto urb_submit_failed; } + ictx->dev_present_intf1 = true; + mutex_unlock(&ictx->lock); return ictx; -- cgit From 9688efda3fb0abb487ae44ced1dd02d14a4312c4 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:07 -0300 Subject: [media] move ati_remote driver from input/misc to media/rc The driver will be migrated to the RC driver API in a following commit. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 20 +- drivers/media/rc/Makefile | 1 + drivers/media/rc/ati_remote.c | 867 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 886 insertions(+), 2 deletions(-) create mode 100644 drivers/media/rc/ati_remote.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 899f783d92fb..756884e007e6 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -4,8 +4,8 @@ menuconfig RC_CORE default INPUT ---help--- Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters. - Currently, all supported devices use InfraRed. + needed in order to support several video capture adapters, + standalone IR receivers/transmitters, and RF receivers. Enable this option if you have a video capture board even if you don't need IR, as otherwise, you may not be able to @@ -108,6 +108,22 @@ config IR_LIRC_CODEC Enable this option to pass raw IR to and from userspace via the LIRC interface. +config RC_ATI_REMOTE + tristate "ATI / X10 USB RF remote control" + depends on USB_ARCH_HAS_HCD + select USB + help + Say Y here if you want to use an ATI or X10 "Lola" USB remote control. + These are RF remotes with USB receivers. + The ATI remote comes with many of ATI's All-In-Wonder video cards. + The X10 "Lola" remote is available at: + + This driver provides mouse pointer, left and right mouse buttons, + and maps all the other remote buttons to keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote. + config IR_ENE tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" depends on PNP diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index f224db027c41..2156e786b557 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters +obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_IR_IMON) += imon.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c new file mode 100644 index 000000000000..53388a558a57 --- /dev/null +++ b/drivers/media/rc/ati_remote.c @@ -0,0 +1,867 @@ +/* + * USB ATI Remote support + * + * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman + * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev + * + * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including + * porting to the 2.6 kernel interfaces, along with other modification + * to better match the style of the existing usb/input drivers. However, the + * protocol and hardware handling is essentially unchanged from 2.1.1. + * + * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by + * Vojtech Pavlik. + * + * Changes: + * + * Feb 2004: Torrey Hoffman + * Version 2.2.0 + * Jun 2004: Torrey Hoffman + * Version 2.2.1 + * Added key repeat support contributed by: + * Vincent Vanackere + * Added support for the "Lola" remote contributed by: + * Seth Cohn + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Hardware & software notes + * + * These remote controls are distributed by ATI as part of their + * "All-In-Wonder" video card packages. The receiver self-identifies as a + * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". + * + * The "Lola" remote is available from X10. See: + * http://www.x10.com/products/lola_sg1.htm + * The Lola is similar to the ATI remote but has no mouse support, and slightly + * different keys. + * + * It is possible to use multiple receivers and remotes on multiple computers + * simultaneously by configuring them to use specific channels. + * + * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. + * Actually, it may even support more, at least in some revisions of the + * hardware. + * + * Each remote can be configured to transmit on one channel as follows: + * - Press and hold the "hand icon" button. + * - When the red LED starts to blink, let go of the "hand icon" button. + * - When it stops blinking, input the channel code as two digits, from 01 + * to 16, and press the hand icon again. + * + * The timing can be a little tricky. Try loading the module with debug=1 + * to have the kernel print out messages about the remote control number + * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. + * + * The driver has a "channel_mask" parameter. This bitmask specifies which + * channels will be ignored by the module. To mask out channels, just add + * all the 2^channel_number values together. + * + * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote + * ignore signals coming from remote controls transmitting on channel 4, but + * accept all other channels. + * + * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be + * ignored. + * + * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this + * parameter are unused. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Module and Version Information, Module Parameters + */ + +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define LOLA_REMOTE_PRODUCT_ID 0x0002 +#define LOLA2_REMOTE_PRODUCT_ID 0x0003 +#define ATI_REMOTE_PRODUCT_ID 0x0004 +#define NVIDIA_REMOTE_PRODUCT_ID 0x0005 +#define MEDION_REMOTE_PRODUCT_ID 0x0006 + +#define DRIVER_VERSION "2.2.1" +#define DRIVER_AUTHOR "Torrey Hoffman " +#define DRIVER_DESC "ATI/X10 RF USB Remote Control" + +#define NAME_BUFSIZE 80 /* size of product name, path buffers */ +#define DATA_BUFSIZE 63 /* size of URB data buffers */ + +/* + * Duplicate event filtering time. + * Sequential, identical KIND_FILTERED inputs with less than + * FILTER_TIME milliseconds between them are considered as repeat + * events. The hardware generates 5 events for the first keypress + * and we have to take this into account for an accurate repeat + * behaviour. + */ +#define FILTER_TIME 60 /* msec */ +#define REPEAT_DELAY 500 /* msec */ + +static unsigned long channel_mask; +module_param(channel_mask, ulong, 0644); +MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +static int repeat_filter = FILTER_TIME; +module_param(repeat_filter, int, 0644); +MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); + +static int repeat_delay = REPEAT_DELAY; +module_param(repeat_delay, int, 0644); +MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); + +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) +#undef err +#define err(format, arg...) printk(KERN_ERR format , ## arg) + +static struct usb_device_id ati_remote_table[] = { + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ati_remote_table); + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 + +/* Device initialization strings */ +static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; +static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; + +struct ati_remote { + struct input_dev *idev; + struct usb_device *udev; + struct usb_interface *interface; + + struct urb *irq_urb; + struct urb *out_urb; + struct usb_endpoint_descriptor *endpoint_in; + struct usb_endpoint_descriptor *endpoint_out; + unsigned char *inbuf; + unsigned char *outbuf; + dma_addr_t inbuf_dma; + dma_addr_t outbuf_dma; + + unsigned char old_data[2]; /* Detect duplicate events */ + unsigned long old_jiffies; + unsigned long acc_jiffies; /* handle acceleration */ + unsigned long first_jiffies; + + unsigned int repeat_count; + + char name[NAME_BUFSIZE]; + char phys[NAME_BUFSIZE]; + + wait_queue_head_t wait; + int send_flags; +}; + +/* "Kinds" of messages sent from the hardware to the driver. */ +#define KIND_END 0 +#define KIND_LITERAL 1 /* Simply pass to input system */ +#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ +#define KIND_LU 3 /* Directional keypad diagonals - left up, */ +#define KIND_RU 4 /* right up, */ +#define KIND_LD 5 /* left down, */ +#define KIND_RD 6 /* right down */ +#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ + +/* Translation table from hardware messages to input events. */ +static const struct { + short kind; + unsigned char data1, data2; + int type; + unsigned int code; + int value; +} ati_remote_tbl[] = { + /* Directional control pad axes */ + {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + /* Directional control pad diagonals */ + {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + + /* "Mouse button" buttons */ + {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + + /* Artificial "doubleclick" events are generated by the hardware. + * They are mapped to the "side" and "extra" mouse buttons here. */ + {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + + /* keyboard. */ + {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, + {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, + {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, + {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, + {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, + {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, + {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, + {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, + {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, + {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, + {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, + {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, + {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, + {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, + {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, + {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, + + /* "special" keys */ + {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ + {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ + {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ + {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ + {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ + {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ + {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ + {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ + {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ + {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ + {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ + {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ + {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ + {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ + {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ + {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ + {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ + {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ + {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ + {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ + {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ + {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ + {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ + {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ + {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ + {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ + {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ + {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ + {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ + {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ + {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ + {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ + + {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} +}; + +/* Local function prototypes */ +static int ati_remote_open (struct input_dev *inputdev); +static void ati_remote_close (struct input_dev *inputdev); +static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); +static void ati_remote_irq_out (struct urb *urb); +static void ati_remote_irq_in (struct urb *urb); +static void ati_remote_input_report (struct urb *urb); +static int ati_remote_initialize (struct ati_remote *ati_remote); +static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); +static void ati_remote_disconnect (struct usb_interface *interface); + +/* usb specific object to register with the usb subsystem */ +static struct usb_driver ati_remote_driver = { + .name = "ati_remote", + .probe = ati_remote_probe, + .disconnect = ati_remote_disconnect, + .id_table = ati_remote_table, +}; + +/* + * ati_remote_dump_input + */ +static void ati_remote_dump(struct device *dev, unsigned char *data, + unsigned int len) +{ + if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) + dev_warn(dev, "Weird byte 0x%02x\n", data[0]); + else if (len == 4) + dev_warn(dev, "Weird key %02x %02x %02x %02x\n", + data[0], data[1], data[2], data[3]); + else + dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + len, data[0], data[1], data[2], data[3], data[4], data[5]); +} + +/* + * ati_remote_open + */ +static int ati_remote_open(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + + /* On first open, submit the read urb which was set up previously. */ + ati_remote->irq_urb->dev = ati_remote->udev; + if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { + dev_err(&ati_remote->interface->dev, + "%s: usb_submit_urb failed!\n", __func__); + return -EIO; + } + + return 0; +} + +/* + * ati_remote_close + */ +static void ati_remote_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + + usb_kill_urb(ati_remote->irq_urb); +} + +/* + * ati_remote_irq_out + */ +static void ati_remote_irq_out(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + + if (urb->status) { + dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", + __func__, urb->status); + return; + } + + ati_remote->send_flags |= SEND_FLAG_COMPLETE; + wmb(); + wake_up(&ati_remote->wait); +} + +/* + * ati_remote_sendpacket + * + * Used to send device initialization strings + */ +static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) +{ + int retval = 0; + + /* Set up out_urb */ + memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); + ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); + + ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; + ati_remote->out_urb->dev = ati_remote->udev; + ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; + + retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); + if (retval) { + dev_dbg(&ati_remote->interface->dev, + "sendpacket: usb_submit_urb failed: %d\n", retval); + return retval; + } + + wait_event_timeout(ati_remote->wait, + ((ati_remote->out_urb->status != -EINPROGRESS) || + (ati_remote->send_flags & SEND_FLAG_COMPLETE)), + HZ); + usb_kill_urb(ati_remote->out_urb); + + return retval; +} + +/* + * ati_remote_event_lookup + */ +static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) +{ + int i; + + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + /* + * Decide if the table entry matches the remote input. + */ + if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && + ((((ati_remote_tbl[i].data1 >> 4) - + (d1 >> 4) + rem) & 0x0f) == 0x0f) && + (ati_remote_tbl[i].data2 == d2)) + return i; + + } + return -1; +} + +/* + * ati_remote_compute_accel + * + * Implements acceleration curve for directional control pad + * If elapsed time since last event is > 1/4 second, user "stopped", + * so reset acceleration. Otherwise, user is probably holding the control + * pad down, so we increase acceleration, ramping up over two seconds to + * a maximum speed. + */ +static int ati_remote_compute_accel(struct ati_remote *ati_remote) +{ + static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; + unsigned long now = jiffies; + int acc; + + if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { + acc = 1; + ati_remote->acc_jiffies = now; + } + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) + acc = accel[0]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) + acc = accel[1]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) + acc = accel[2]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) + acc = accel[3]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) + acc = accel[4]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) + acc = accel[5]; + else + acc = accel[6]; + + return acc; +} + +/* + * ati_remote_report_input + */ +static void ati_remote_input_report(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + unsigned char *data= ati_remote->inbuf; + struct input_dev *dev = ati_remote->idev; + int index, acc; + int remote_num; + + /* Deal with strange looking inputs */ + if ( (urb->actual_length != 4) || (data[0] != 0x14) || + ((data[3] & 0x0f) != 0x00) ) { + ati_remote_dump(&urb->dev->dev, data, urb->actual_length); + return; + } + + /* Mask unwanted remote channels. */ + /* note: remote_num is 0-based, channel 1 on remote == 0 here */ + remote_num = (data[3] >> 4) & 0x0f; + if (channel_mask & (1 << (remote_num + 1))) { + dbginfo(&ati_remote->interface->dev, + "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", + remote_num, data[1], data[2], channel_mask); + return; + } + + /* Look up event code index in translation table */ + index = ati_remote_event_lookup(remote_num, data[1], data[2]); + if (index < 0) { + dev_warn(&ati_remote->interface->dev, + "Unknown input from channel 0x%02x: data %02x,%02x\n", + remote_num, data[1], data[2]); + return; + } + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + + if (ati_remote_tbl[index].kind == KIND_LITERAL) { + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value); + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + return; + } + + if (ati_remote_tbl[index].kind == KIND_FILTERED) { + unsigned long now = jiffies; + + /* Filter duplicate events which happen "too close" together. */ + if (ati_remote->old_data[0] == data[1] && + ati_remote->old_data[1] == data[2] && + time_before(now, ati_remote->old_jiffies + + msecs_to_jiffies(repeat_filter))) { + ati_remote->repeat_count++; + } else { + ati_remote->repeat_count = 0; + ati_remote->first_jiffies = now; + } + + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + ati_remote->old_jiffies = now; + + /* Ensure we skip at least the 4 first duplicate events (generated + * by a single keypress), and continue skipping until repeat_delay + * msecs have passed + */ + if (ati_remote->repeat_count > 0 && + (ati_remote->repeat_count < 5 || + time_before(now, ati_remote->first_jiffies + + msecs_to_jiffies(repeat_delay)))) + return; + + + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 1); + input_sync(dev); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 0); + input_sync(dev); + + } else { + + /* + * Other event kinds are from the directional control pad, and have an + * acceleration factor applied to them. Without this acceleration, the + * control pad is mostly unusable. + */ + acc = ati_remote_compute_accel(ati_remote); + + switch (ati_remote_tbl[index].kind) { + case KIND_ACCEL: + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value * acc); + break; + case KIND_LU: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_RU: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_LD: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, acc); + break; + case KIND_RD: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, acc); + break; + default: + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); + } + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + } +} + +/* + * ati_remote_irq_in + */ +static void ati_remote_irq_in(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + int retval; + + switch (urb->status) { + case 0: /* success */ + ati_remote_input_report(urb); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", + __func__); + return; + default: /* error */ + dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + __func__, urb->status); + } + + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", + __func__, retval); +} + +/* + * ati_remote_alloc_buffers + */ +static int ati_remote_alloc_buffers(struct usb_device *udev, + struct ati_remote *ati_remote) +{ + ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + return -1; + + ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + return -1; + + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + return -1; + + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + return -1; + + return 0; +} + +/* + * ati_remote_free_buffers + */ +static void ati_remote_free_buffers(struct ati_remote *ati_remote) +{ + usb_free_urb(ati_remote->irq_urb); + usb_free_urb(ati_remote->out_urb); + + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); + + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, + ati_remote->outbuf, ati_remote->outbuf_dma); +} + +static void ati_remote_input_init(struct ati_remote *ati_remote) +{ + struct input_dev *idev = ati_remote->idev; + int i; + + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); + idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | + BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); + idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) + if (ati_remote_tbl[i].type == EV_KEY) + set_bit(ati_remote_tbl[i].code, idev->keybit); + + input_set_drvdata(idev, ati_remote); + + idev->open = ati_remote_open; + idev->close = ati_remote_close; + + idev->name = ati_remote->name; + idev->phys = ati_remote->phys; + + usb_to_input_id(ati_remote->udev, &idev->id); + idev->dev.parent = &ati_remote->udev->dev; +} + +static int ati_remote_initialize(struct ati_remote *ati_remote) +{ + struct usb_device *udev = ati_remote->udev; + int pipe, maxp; + + init_waitqueue_head(&ati_remote->wait); + + /* Set up irq_urb */ + pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, + maxp, ati_remote_irq_in, ati_remote, + ati_remote->endpoint_in->bInterval); + ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; + ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* Set up out_urb */ + pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, + maxp, ati_remote_irq_out, ati_remote, + ati_remote->endpoint_out->bInterval); + ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; + ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* send initialization strings */ + if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || + (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { + dev_err(&ati_remote->interface->dev, + "Initializing ati_remote hardware failed.\n"); + return -EIO; + } + + return 0; +} + +/* + * ati_remote_probe + */ +static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_host = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; + struct ati_remote *ati_remote; + struct input_dev *input_dev; + int err = -ENOMEM; + + if (iface_host->desc.bNumEndpoints != 2) { + err("%s: Unexpected desc.bNumEndpoints\n", __func__); + return -ENODEV; + } + + endpoint_in = &iface_host->endpoint[0].desc; + endpoint_out = &iface_host->endpoint[1].desc; + + if (!usb_endpoint_is_int_in(endpoint_in)) { + err("%s: Unexpected endpoint_in\n", __func__); + return -ENODEV; + } + if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { + err("%s: endpoint_in message size==0? \n", __func__); + return -ENODEV; + } + + ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ati_remote || !input_dev) + goto fail1; + + /* Allocate URB buffers, URBs */ + if (ati_remote_alloc_buffers(udev, ati_remote)) + goto fail2; + + ati_remote->endpoint_in = endpoint_in; + ati_remote->endpoint_out = endpoint_out; + ati_remote->udev = udev; + ati_remote->idev = input_dev; + ati_remote->interface = interface; + + usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); + strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + + if (udev->manufacturer) + strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); + + if (udev->product) + snprintf(ati_remote->name, sizeof(ati_remote->name), + "%s %s", ati_remote->name, udev->product); + + if (!strlen(ati_remote->name)) + snprintf(ati_remote->name, sizeof(ati_remote->name), + DRIVER_DESC "(%04x,%04x)", + le16_to_cpu(ati_remote->udev->descriptor.idVendor), + le16_to_cpu(ati_remote->udev->descriptor.idProduct)); + + ati_remote_input_init(ati_remote); + + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ + err = ati_remote_initialize(ati_remote); + if (err) + goto fail3; + + /* Set up and register input device */ + err = input_register_device(ati_remote->idev); + if (err) + goto fail3; + + usb_set_intfdata(interface, ati_remote); + return 0; + + fail3: usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + fail2: ati_remote_free_buffers(ati_remote); + fail1: input_free_device(input_dev); + kfree(ati_remote); + return err; +} + +/* + * ati_remote_disconnect + */ +static void ati_remote_disconnect(struct usb_interface *interface) +{ + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + if (!ati_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + input_unregister_device(ati_remote->idev); + ati_remote_free_buffers(ati_remote); + kfree(ati_remote); +} + +/* + * ati_remote_init + */ +static int __init ati_remote_init(void) +{ + int result; + + result = usb_register(&ati_remote_driver); + if (result) + printk(KERN_ERR KBUILD_MODNAME + ": usb_register error #%d\n", result); + else + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + + return result; +} + +/* + * ati_remote_exit + */ +static void __exit ati_remote_exit(void) +{ + usb_deregister(&ati_remote_driver); +} + +/* + * module specification + */ + +module_init(ati_remote_init); +module_exit(ati_remote_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); -- cgit From c34516e599d9c00388ab49e88f3e9e38f8fc5346 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:08 -0300 Subject: [media] ati_remote: migrate to the rc subsystem The keycode mangling algorithm is kept the same, so the new external keymap has the same values as the old static table. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 + drivers/media/rc/ati_remote.c | 262 +++++++++++++++++++++------------- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-ati-x10.c | 103 +++++++++++++ 4 files changed, 268 insertions(+), 99 deletions(-) create mode 100644 drivers/media/rc/keymaps/rc-ati-x10.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 756884e007e6..ea45f35571a9 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -111,6 +111,7 @@ config IR_LIRC_CODEC config RC_ATI_REMOTE tristate "ATI / X10 USB RF remote control" depends on USB_ARCH_HAS_HCD + depends on RC_CORE select USB help Say Y here if you want to use an ATI or X10 "Lola" USB remote control. diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 53388a558a57..4b4509a6d9d5 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -1,6 +1,7 @@ /* * USB ATI Remote support * + * Copyright (c) 2011 Anssi Hannula * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev * @@ -90,9 +91,11 @@ #include #include #include +#include #include #include #include +#include /* * Module and Version Information, Module Parameters @@ -139,6 +142,10 @@ static int repeat_delay = REPEAT_DELAY; module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); +static bool mouse = true; +module_param(mouse, bool, 0444); +MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); + #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) @@ -167,6 +174,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; struct ati_remote { struct input_dev *idev; + struct rc_dev *rdev; struct usb_device *udev; struct usb_interface *interface; @@ -186,11 +194,16 @@ struct ati_remote { unsigned int repeat_count; - char name[NAME_BUFSIZE]; - char phys[NAME_BUFSIZE]; + char rc_name[NAME_BUFSIZE]; + char rc_phys[NAME_BUFSIZE]; + char mouse_name[NAME_BUFSIZE]; + char mouse_phys[NAME_BUFSIZE]; wait_queue_head_t wait; int send_flags; + + int users; /* 0-2, users are rc and input */ + struct mutex open_mutex; }; /* "Kinds" of messages sent from the hardware to the driver. */ @@ -233,64 +246,11 @@ static const struct { {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ - /* keyboard. */ - {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, - {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, - {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, - {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, - {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, - {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, - {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, - {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, - {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, - {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, - {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, - {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, - {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, - {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, - {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, - {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, - - /* "special" keys */ - {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ - {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ - {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ - {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ - {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ - {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ - {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ - {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ - {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ - {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ - {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ - {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ - {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ - {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ - {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ - {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ - {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ - {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ - {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ - {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ - {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ - {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ - {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ - {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ - {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ - {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ - {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ - {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ - {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ - {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ - {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ - {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ - + /* Non-mouse events are handled by rc-core */ {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} }; /* Local function prototypes */ -static int ati_remote_open (struct input_dev *inputdev); -static void ati_remote_close (struct input_dev *inputdev); static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); static void ati_remote_irq_out (struct urb *urb); static void ati_remote_irq_in (struct urb *urb); @@ -326,29 +286,60 @@ static void ati_remote_dump(struct device *dev, unsigned char *data, /* * ati_remote_open */ -static int ati_remote_open(struct input_dev *inputdev) +static int ati_remote_open(struct ati_remote *ati_remote) { - struct ati_remote *ati_remote = input_get_drvdata(inputdev); + int err = 0; + + mutex_lock(&ati_remote->open_mutex); + + if (ati_remote->users++ != 0) + goto out; /* one was already active */ /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __func__); - return -EIO; + err = -EIO; } - return 0; +out: mutex_unlock(&ati_remote->open_mutex); + return err; } /* * ati_remote_close */ -static void ati_remote_close(struct input_dev *inputdev) +static void ati_remote_close(struct ati_remote *ati_remote) +{ + mutex_lock(&ati_remote->open_mutex); + if (--ati_remote->users == 0) + usb_kill_urb(ati_remote->irq_urb); + mutex_unlock(&ati_remote->open_mutex); +} + +static int ati_remote_input_open(struct input_dev *inputdev) { struct ati_remote *ati_remote = input_get_drvdata(inputdev); + return ati_remote_open(ati_remote); +} - usb_kill_urb(ati_remote->irq_urb); +static void ati_remote_input_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + ati_remote_close(ati_remote); +} + +static int ati_remote_rc_open(struct rc_dev *rdev) +{ + struct ati_remote *ati_remote = rdev->priv; + return ati_remote_open(ati_remote); +} + +static void ati_remote_rc_close(struct rc_dev *rdev) +{ + struct ati_remote *ati_remote = rdev->priv; + ati_remote_close(ati_remote); } /* @@ -413,10 +404,8 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) /* * Decide if the table entry matches the remote input. */ - if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && - ((((ati_remote_tbl[i].data1 >> 4) - - (d1 >> 4) + rem) & 0x0f) == 0x0f) && - (ati_remote_tbl[i].data2 == d2)) + if (ati_remote_tbl[i].data1 == d1 && + ati_remote_tbl[i].data2 == d2) return i; } @@ -468,8 +457,10 @@ static void ati_remote_input_report(struct urb *urb) struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; struct input_dev *dev = ati_remote->idev; - int index, acc; + int index = -1; + int acc; int remote_num; + unsigned char scancode[2]; /* Deal with strange looking inputs */ if ( (urb->actual_length != 4) || (data[0] != 0x14) || @@ -488,19 +479,26 @@ static void ati_remote_input_report(struct urb *urb) return; } - /* Look up event code index in translation table */ - index = ati_remote_event_lookup(remote_num, data[1], data[2]); - if (index < 0) { - dev_warn(&ati_remote->interface->dev, - "Unknown input from channel 0x%02x: data %02x,%02x\n", - remote_num, data[1], data[2]); - return; - } - dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", - remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); + + scancode[1] = data[2]; + + /* Look up event code index in mouse translation table. */ + index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); + + if (index >= 0) { + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + if (!dev) + return; /* no mouse device */ + } else + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n", + remote_num, data[1], data[2], scancode[0], scancode[1]); - if (ati_remote_tbl[index].kind == KIND_LITERAL) { + + if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) { input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, ati_remote_tbl[index].value); @@ -510,7 +508,7 @@ static void ati_remote_input_report(struct urb *urb) return; } - if (ati_remote_tbl[index].kind == KIND_FILTERED) { + if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) { unsigned long now = jiffies; /* Filter duplicate events which happen "too close" together. */ @@ -538,6 +536,19 @@ static void ati_remote_input_report(struct urb *urb) msecs_to_jiffies(repeat_delay)))) return; + if (index < 0) { + /* Not a mouse event, hand it to rc-core. */ + u32 rc_code = (scancode[0] << 8) | scancode[1]; + + /* + * We don't use the rc-core repeat handling yet as + * it would cause ghost repeats which would be a + * regression for this driver. + */ + rc_keydown_notimeout(ati_remote->rdev, rc_code, 0); + rc_keyup(ati_remote->rdev); + return; + } input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, 1); @@ -675,16 +686,37 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) input_set_drvdata(idev, ati_remote); - idev->open = ati_remote_open; - idev->close = ati_remote_close; + idev->open = ati_remote_input_open; + idev->close = ati_remote_input_close; - idev->name = ati_remote->name; - idev->phys = ati_remote->phys; + idev->name = ati_remote->mouse_name; + idev->phys = ati_remote->mouse_phys; usb_to_input_id(ati_remote->udev, &idev->id); idev->dev.parent = &ati_remote->udev->dev; } +static void ati_remote_rc_init(struct ati_remote *ati_remote) +{ + struct rc_dev *rdev = ati_remote->rdev; + + rdev->priv = ati_remote; + rdev->driver_type = RC_DRIVER_SCANCODE; + rdev->allowed_protos = RC_TYPE_OTHER; + rdev->driver_name = "ati_remote"; + + rdev->open = ati_remote_rc_open; + rdev->close = ati_remote_rc_close; + + rdev->input_name = ati_remote->rc_name; + rdev->input_phys = ati_remote->rc_phys; + + usb_to_input_id(ati_remote->udev, &rdev->input_id); + rdev->dev.parent = &ati_remote->udev->dev; + + rdev->map_name = RC_MAP_ATI_X10; +} + static int ati_remote_initialize(struct ati_remote *ati_remote) { struct usb_device *udev = ati_remote->udev; @@ -735,6 +767,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; struct ati_remote *ati_remote; struct input_dev *input_dev; + struct rc_dev *rc_dev; int err = -ENOMEM; if (iface_host->desc.bNumEndpoints != 2) { @@ -755,8 +788,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de } ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ati_remote || !input_dev) + rc_dev = rc_allocate_device(); + if (!ati_remote || !rc_dev) goto fail1; /* Allocate URB buffers, URBs */ @@ -766,44 +799,73 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote->endpoint_in = endpoint_in; ati_remote->endpoint_out = endpoint_out; ati_remote->udev = udev; - ati_remote->idev = input_dev; + ati_remote->rdev = rc_dev; ati_remote->interface = interface; - usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); - strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys)); + strlcpy(ati_remote->mouse_phys, ati_remote->rc_phys, + sizeof(ati_remote->mouse_phys)); + + strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys)); + strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys)); if (udev->manufacturer) - strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); + strlcpy(ati_remote->rc_name, udev->manufacturer, + sizeof(ati_remote->rc_name)); if (udev->product) - snprintf(ati_remote->name, sizeof(ati_remote->name), - "%s %s", ati_remote->name, udev->product); + snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), + "%s %s", ati_remote->rc_name, udev->product); - if (!strlen(ati_remote->name)) - snprintf(ati_remote->name, sizeof(ati_remote->name), + if (!strlen(ati_remote->rc_name)) + snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), DRIVER_DESC "(%04x,%04x)", le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idProduct)); - ati_remote_input_init(ati_remote); + snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name), + "%s mouse", ati_remote->rc_name); + + ati_remote_rc_init(ati_remote); + mutex_init(&ati_remote->open_mutex); /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ err = ati_remote_initialize(ati_remote); if (err) goto fail3; - /* Set up and register input device */ - err = input_register_device(ati_remote->idev); + /* Set up and register rc device */ + err = rc_register_device(ati_remote->rdev); if (err) goto fail3; + /* use our delay for rc_dev */ + ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay; + + /* Set up and register mouse input device */ + if (mouse) { + input_dev = input_allocate_device(); + if (!input_dev) + goto fail4; + + ati_remote->idev = input_dev; + ati_remote_input_init(ati_remote); + err = input_register_device(input_dev); + + if (err) + goto fail5; + } + usb_set_intfdata(interface, ati_remote); return 0; + fail5: input_free_device(input_dev); + fail4: rc_unregister_device(rc_dev); + rc_dev = NULL; fail3: usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); fail2: ati_remote_free_buffers(ati_remote); - fail1: input_free_device(input_dev); + fail1: rc_free_device(rc_dev); kfree(ati_remote); return err; } @@ -824,7 +886,9 @@ static void ati_remote_disconnect(struct usb_interface *interface) usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); - input_unregister_device(ati_remote->idev); + if (ati_remote->idev) + input_unregister_device(ati_remote->idev); + rc_unregister_device(ati_remote->rdev); ati_remote_free_buffers(ati_remote); kfree(ati_remote); } diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index b57fc83fb4d2..8dd9fdf45c29 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-apac-viewcomp.o \ rc-asus-pc39.o \ rc-ati-tv-wonder-hd-600.o \ + rc-ati-x10.o \ rc-avermedia-a16d.o \ rc-avermedia.o \ rc-avermedia-cardbus.o \ diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c new file mode 100644 index 000000000000..f3397f8ab876 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -0,0 +1,103 @@ +/* + * ATI X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * This file is based on the static generic keytable previously found in + * ati_remote.c, which is + * Copyright (c) 2004 Torrey Hoffman + * Copyright (c) 2002 Vladimir Dergachev + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table ati_x10[] = { + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xc500, KEY_A }, + { 0xc601, KEY_B }, + { 0xde19, KEY_C }, + { 0xe01b, KEY_D }, + { 0xe621, KEY_E }, + { 0xe823, KEY_F }, + + { 0xdd18, KEY_KPENTER }, /* "check" */ + { 0xdb16, KEY_MENU }, /* "menu" */ + { 0xc702, KEY_POWER }, /* Power */ + { 0xc803, KEY_TV }, /* TV */ + { 0xc904, KEY_DVD }, /* DVD */ + { 0xca05, KEY_WWW }, /* WEB */ + { 0xcb06, KEY_BOOKMARKS }, /* "book" */ + { 0xcc07, KEY_EDIT }, /* "hand" */ + { 0xe11c, KEY_COFFEE }, /* "timer" */ + { 0xe520, KEY_FRONT }, /* "max" */ + { 0xe21d, KEY_LEFT }, /* left */ + { 0xe41f, KEY_RIGHT }, /* right */ + { 0xe722, KEY_DOWN }, /* down */ + { 0xdf1a, KEY_UP }, /* up */ + { 0xe31e, KEY_OK }, /* "OK" */ + { 0xce09, KEY_VOLUMEDOWN }, /* VOL + */ + { 0xcd08, KEY_VOLUMEUP }, /* VOL - */ + { 0xcf0a, KEY_MUTE }, /* MUTE */ + { 0xd00b, KEY_CHANNELUP }, /* CH + */ + { 0xd10c, KEY_CHANNELDOWN },/* CH - */ + { 0xec27, KEY_RECORD }, /* ( o) red */ + { 0xea25, KEY_PLAY }, /* ( >) */ + { 0xe924, KEY_REWIND }, /* (<<) */ + { 0xeb26, KEY_FORWARD }, /* (>>) */ + { 0xed28, KEY_STOP }, /* ([]) */ + { 0xee29, KEY_PAUSE }, /* ('') */ + { 0xf02b, KEY_PREVIOUS }, /* (<-) */ + { 0xef2a, KEY_NEXT }, /* (>+) */ + { 0xf22d, KEY_INFO }, /* PLAYING */ + { 0xf32e, KEY_HOME }, /* TOP */ + { 0xf42f, KEY_END }, /* END */ + { 0xf530, KEY_SELECT }, /* SELECT */ +}; + +static struct rc_map_list ati_x10_map = { + .map = { + .scan = ati_x10, + .size = ARRAY_SIZE(ati_x10), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_ATI_X10, + } +}; + +static int __init init_rc_map_ati_x10(void) +{ + return rc_map_register(&ati_x10_map); +} + +static void __exit exit_rc_map_ati_x10(void) +{ + rc_map_unregister(&ati_x10_map); +} + +module_init(init_rc_map_ati_x10) +module_exit(exit_rc_map_ati_x10) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); -- cgit From 44fd0b600fbc21de9d771f0a5db79d24b321fce7 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:09 -0300 Subject: [media] ati_remote: parent input devices to usb interface Parent the input devices to usb_interface instead of usb_device. This fixes (at least) persistent input device nodes. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 4b4509a6d9d5..7a47d7e73b57 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -693,7 +693,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->phys = ati_remote->mouse_phys; usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev.parent = &ati_remote->udev->dev; + idev->dev.parent = &ati_remote->interface->dev; } static void ati_remote_rc_init(struct ati_remote *ati_remote) @@ -712,7 +712,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->input_phys = ati_remote->rc_phys; usb_to_input_id(ati_remote->udev, &rdev->input_id); - rdev->dev.parent = &ati_remote->udev->dev; + rdev->dev.parent = &ati_remote->interface->dev; rdev->map_name = RC_MAP_ATI_X10; } -- cgit From 0224e0401f0b18e1f5fce010558b12fc24257e37 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:10 -0300 Subject: [media] ati_remote: fix check for a weird byte The ati_remote_dump() function tries to not print "Weird byte" warning for 1-byte responses that contain 0xff or 0x00, but it doesn't work properly as it simply falls back to the "Weird data" warning in the else clause. Fix that by adding an inner if clause. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 7a47d7e73b57..92f2b1bcef4a 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -273,9 +273,10 @@ static struct usb_driver ati_remote_driver = { static void ati_remote_dump(struct device *dev, unsigned char *data, unsigned int len) { - if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - dev_warn(dev, "Weird byte 0x%02x\n", data[0]); - else if (len == 4) + if (len == 1) { + if (data[0] != (unsigned char)0xff && data[0] != 0x00) + dev_warn(dev, "Weird byte 0x%02x\n", data[0]); + } else if (len == 4) dev_warn(dev, "Weird key %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]); else -- cgit From 175fcecf79b4698c7beea5810326dba66a56ea39 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:11 -0300 Subject: [media] ati_remote: add keymap for Medion X10 RF remote Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 17 +++-- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-medion-x10.c | 116 +++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 drivers/media/rc/keymaps/rc-medion-x10.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 92f2b1bcef4a..94d241d37619 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -151,11 +151,11 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); #define err(format, arg...) printk(KERN_ERR format , ## arg) static struct usb_device_id ati_remote_table[] = { - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_MEDION_X10 }, {} /* Terminating entry */ }; @@ -714,8 +714,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) usb_to_input_id(ati_remote->udev, &rdev->input_id); rdev->dev.parent = &ati_remote->interface->dev; - - rdev->map_name = RC_MAP_ATI_X10; } static int ati_remote_initialize(struct ati_remote *ati_remote) @@ -827,6 +825,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name), "%s mouse", ati_remote->rc_name); + if (id->driver_info) + rc_dev->map_name = (const char *)id->driver_info; + else + rc_dev->map_name = RC_MAP_ATI_X10; + ati_remote_rc_init(ati_remote); mutex_init(&ati_remote->open_mutex); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 8dd9fdf45c29..2b97b4327ab2 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-lirc.o \ rc-lme2510.o \ rc-manli.o \ + rc-medion-x10.o \ rc-msi-digivox-ii.o \ rc-msi-digivox-iii.o \ rc-msi-tvanywhere.o \ diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c new file mode 100644 index 000000000000..5fc57468daf4 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -0,0 +1,116 @@ +/* + * Medion X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * This file is based on a keytable provided by + * Jan Losinski + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table medion_x10[] = { + { 0xf12c, KEY_TV }, /* TV */ + { 0xf22d, KEY_VCR }, /* VCR */ + { 0xc904, KEY_DVD }, /* DVD */ + { 0xcb06, KEY_AUDIO }, /* MUSIC */ + + { 0xf32e, KEY_RADIO }, /* RADIO */ + { 0xca05, KEY_DIRECTORY }, /* PHOTO */ + { 0xf42f, KEY_INFO }, /* TV-PREVIEW */ + { 0xf530, KEY_LIST }, /* CHANNEL-LST */ + + { 0xe01b, KEY_SETUP }, /* SETUP */ + { 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */ + + { 0xcd08, KEY_VOLUMEDOWN }, /* VOL - */ + { 0xce09, KEY_VOLUMEUP }, /* VOL + */ + { 0xd00b, KEY_CHANNELUP }, /* CHAN + */ + { 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */ + { 0xc500, KEY_MUTE }, /* MUTE */ + + { 0xf732, KEY_RED }, /* red */ + { 0xf833, KEY_GREEN }, /* green */ + { 0xf934, KEY_YELLOW }, /* yellow */ + { 0xfa35, KEY_BLUE }, /* blue */ + { 0xdb16, KEY_TEXT }, /* TXT */ + + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */ + { 0xe520, KEY_DELETE }, /* DELETE */ + + { 0xfb36, KEY_KEYBOARD }, /* RENAME */ + { 0xdd18, KEY_SCREEN }, /* SNAPSHOT */ + + { 0xdf1a, KEY_UP }, /* up */ + { 0xe722, KEY_DOWN }, /* down */ + { 0xe21d, KEY_LEFT }, /* left */ + { 0xe41f, KEY_RIGHT }, /* right */ + { 0xe31e, KEY_OK }, /* OK */ + + { 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */ + { 0xfd38, KEY_EDIT }, /* EDIT IMAGE */ + + { 0xe924, KEY_REWIND }, /* rewind (<<) */ + { 0xea25, KEY_PLAY }, /* play ( >) */ + { 0xeb26, KEY_FORWARD }, /* forward (>>) */ + { 0xec27, KEY_RECORD }, /* record ( o) */ + { 0xed28, KEY_STOP }, /* stop ([]) */ + { 0xee29, KEY_PAUSE }, /* pause ('') */ + + { 0xe621, KEY_PREVIOUS }, /* prev */ + { 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */ + { 0xe823, KEY_NEXT }, /* next */ + { 0xde19, KEY_MENU }, /* MENU */ + { 0xff3a, KEY_LANGUAGE }, /* AUDIO */ + + { 0xc702, KEY_POWER }, /* POWER */ +}; + +static struct rc_map_list medion_x10_map = { + .map = { + .scan = medion_x10, + .size = ARRAY_SIZE(medion_x10), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_MEDION_X10, + } +}; + +static int __init init_rc_map_medion_x10(void) +{ + return rc_map_register(&medion_x10_map); +} + +static void __exit exit_rc_map_medion_x10(void) +{ + rc_map_unregister(&medion_x10_map); +} + +module_init(init_rc_map_medion_x10) +module_exit(exit_rc_map_medion_x10) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); -- cgit From 999d6bc9b142a531fb10652c64de51e2ad672a1e Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:12 -0300 Subject: [media] ati_remote: add support for SnapStream Firefly remote The protocol differs by having two toggle bits in the scancode. Since one of the bits is otherwise unused, we can safely handle the bits unconditionally. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 15 +++- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-snapstream-firefly.c | 106 +++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 drivers/media/rc/keymaps/rc-snapstream-firefly.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 94d241d37619..303f22ea04c0 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -107,6 +107,7 @@ #define ATI_REMOTE_PRODUCT_ID 0x0004 #define NVIDIA_REMOTE_PRODUCT_ID 0x0005 #define MEDION_REMOTE_PRODUCT_ID 0x0006 +#define FIREFLY_REMOTE_PRODUCT_ID 0x0008 #define DRIVER_VERSION "2.2.1" #define DRIVER_AUTHOR "Torrey Hoffman " @@ -156,6 +157,7 @@ static struct usb_device_id ati_remote_table[] = { { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_MEDION_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY }, {} /* Terminating entry */ }; @@ -482,7 +484,15 @@ static void ati_remote_input_report(struct urb *urb) scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); - scancode[1] = data[2]; + /* + * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code, + * so we have to clear them. The first bit is a bit tricky as the + * "non-toggled" state depends on remote_num, so we xor it with the + * second bit which is only used for toggle. + */ + scancode[0] ^= (data[2] & 0x80); + + scancode[1] = data[2] & ~0x80; /* Look up event code index in mouse translation table. */ index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); @@ -546,7 +556,8 @@ static void ati_remote_input_report(struct urb *urb) * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, rc_code, 0); + rc_keydown_notimeout(ati_remote->rdev, rc_code, + data[2]); rc_keyup(ati_remote->rdev); return; } diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 2b97b4327ab2..36e4d5e8dd6a 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hauppauge.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ + rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tbs-nec.o \ rc-technisat-usb2.o \ diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c new file mode 100644 index 000000000000..5836aa216621 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -0,0 +1,106 @@ +/* + * SnapStream Firefly X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table snapstream_firefly[] = { + { 0xf12c, KEY_ZOOM }, /* Maximize */ + { 0xc702, KEY_CLOSE }, + + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xdb16, KEY_BACK }, + { 0xdd18, KEY_KPENTER }, /* ent */ + + { 0xce09, KEY_VOLUMEUP }, + { 0xcd08, KEY_VOLUMEDOWN }, + { 0xcf0a, KEY_MUTE }, + { 0xd00b, KEY_CHANNELUP }, + { 0xd10c, KEY_CHANNELDOWN }, + { 0xc500, KEY_VENDOR }, /* firefly */ + + { 0xf32e, KEY_INFO }, + { 0xf42f, KEY_OPTION }, + + { 0xe21d, KEY_LEFT }, + { 0xe41f, KEY_RIGHT }, + { 0xe722, KEY_DOWN }, + { 0xdf1a, KEY_UP }, + { 0xe31e, KEY_OK }, + + { 0xe11c, KEY_MENU }, + { 0xe520, KEY_EXIT }, + + { 0xec27, KEY_RECORD }, + { 0xea25, KEY_PLAY }, + { 0xed28, KEY_STOP }, + { 0xe924, KEY_REWIND }, + { 0xeb26, KEY_FORWARD }, + { 0xee29, KEY_PAUSE }, + { 0xf02b, KEY_PREVIOUS }, + { 0xef2a, KEY_NEXT }, + + { 0xcb06, KEY_AUDIO }, /* Music */ + { 0xca05, KEY_IMAGES }, /* Photos */ + { 0xc904, KEY_DVD }, + { 0xc803, KEY_TV }, + { 0xcc07, KEY_VIDEO }, + + { 0xc601, KEY_HELP }, + { 0xf22d, KEY_MODE }, /* Mouse */ + + { 0xde19, KEY_A }, + { 0xe01b, KEY_B }, + { 0xe621, KEY_C }, + { 0xe823, KEY_D }, +}; + +static struct rc_map_list snapstream_firefly_map = { + .map = { + .scan = snapstream_firefly, + .size = ARRAY_SIZE(snapstream_firefly), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_SNAPSTREAM_FIREFLY, + } +}; + +static int __init init_rc_map_snapstream_firefly(void) +{ + return rc_map_register(&snapstream_firefly_map); +} + +static void __exit exit_rc_map_snapstream_firefly(void) +{ + rc_map_unregister(&snapstream_firefly_map); +} + +module_init(init_rc_map_snapstream_firefly) +module_exit(exit_rc_map_snapstream_firefly) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); -- cgit From 3a7a62378be538944ff00904b8e0b795fe16609a Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:13 -0300 Subject: [media] ati_remote: update Kconfig description The ati_remote driver supports more remotes nowadays, update the description to reflect that. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index ea45f35571a9..aeb7f43dfb65 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -109,16 +109,18 @@ config IR_LIRC_CODEC the LIRC interface. config RC_ATI_REMOTE - tristate "ATI / X10 USB RF remote control" + tristate "ATI / X10 based USB RF remote controls" depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB help - Say Y here if you want to use an ATI or X10 "Lola" USB remote control. + Say Y here if you want to use an X10 based USB remote control. These are RF remotes with USB receivers. - The ATI remote comes with many of ATI's All-In-Wonder video cards. - The X10 "Lola" remote is available at: - + + Such devices include the ATI remote that comes with many of ATI's + All-In-Wonder video cards, the X10 "Lola" remote, NVIDIA RF remote, + Medion RF remote, and SnapStream FireFly remote. + This driver provides mouse pointer, left and right mouse buttons, and maps all the other remote buttons to keypress events. -- cgit From 547d42eac107f027e6101b828f9e4075f2fbcc7c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Sep 2011 15:33:27 -0300 Subject: [media] rc tables: include linux/module.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents errors when merging with -next: drivers/media/rc/keymaps/rc-snapstream-firefly.c:105:16: error: expected declaration specifiers or ‘...’ before string constant drivers/media/rc/keymaps/rc-snapstream-firefly.c:106:15: error: expected declaration specifiers or ‘...’ before string constant Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-ati-x10.c | 1 + drivers/media/rc/keymaps/rc-medion-x10.c | 1 + drivers/media/rc/keymaps/rc-snapstream-firefly.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index f3397f8ab876..e1b8b2605c48 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -23,6 +23,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table ati_x10[] = { diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 5fc57468daf4..09e2cc01d110 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -21,6 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table medion_x10[] = { diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index 5836aa216621..ef146520931c 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -18,6 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table snapstream_firefly[] = { -- cgit From 600836cc7b049f3eb47e9b39f379aa4b0926188a Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 23 Sep 2011 10:19:07 -0300 Subject: [media] media, rc: Use static inline functions to kill warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch converts some ifdef'd wrapper functions from macros to static inline functions to kill the following warnings issued by GCC: CC [M] drivers/media/rc/ir-raw.o drivers/media/rc/ir-raw.c: In function ‘init_decoders’: drivers/media/rc/ir-raw.c:353:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:354:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:355:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:356:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:357:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:359:2: warning: statement with no effect [-Wunused-value] Cc: Mauro Carvalho Chehab Cc: "David Härdeman" Cc: Jarod Wilson Cc: Signed-off-by: Pekka Enberg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-core-priv.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 04c2c722b6ec..c6ca870e8b7e 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -162,49 +162,49 @@ void ir_raw_init(void); #ifdef CONFIG_IR_NEC_DECODER_MODULE #define load_nec_decode() request_module("ir-nec-decoder") #else -#define load_nec_decode() 0 +static inline void load_nec_decode(void) { } #endif /* from ir-rc5-decoder.c */ #ifdef CONFIG_IR_RC5_DECODER_MODULE #define load_rc5_decode() request_module("ir-rc5-decoder") #else -#define load_rc5_decode() 0 +static inline void load_rc5_decode(void) { } #endif /* from ir-rc6-decoder.c */ #ifdef CONFIG_IR_RC6_DECODER_MODULE #define load_rc6_decode() request_module("ir-rc6-decoder") #else -#define load_rc6_decode() 0 +static inline void load_rc6_decode(void) { } #endif /* from ir-jvc-decoder.c */ #ifdef CONFIG_IR_JVC_DECODER_MODULE #define load_jvc_decode() request_module("ir-jvc-decoder") #else -#define load_jvc_decode() 0 +static inline void load_jvc_decode(void) { } #endif /* from ir-sony-decoder.c */ #ifdef CONFIG_IR_SONY_DECODER_MODULE #define load_sony_decode() request_module("ir-sony-decoder") #else -#define load_sony_decode() 0 +static inline void load_sony_decode(void) { } #endif /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE #define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") #else -#define load_mce_kbd_decode() 0 +static inline void load_mce_kbd_decode(void) { } #endif /* from ir-lirc-codec.c */ #ifdef CONFIG_IR_LIRC_CODEC_MODULE #define load_lirc_codec() request_module("ir-lirc-codec") #else -#define load_lirc_codec() 0 +static inline void load_lirc_codec(void) { } #endif -- cgit From 06bd801c23939952bc6e1cf65f0e8c0fff09d2d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Oct 2011 02:41:06 -0300 Subject: [media] rc/ir-lirc-codec: cleanup __user tags The code here treated user pointers correctly, but the __user tags weren't used correctly so it caused Sparse warnings: Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index e5eeec4da76e..ec2e67fd236b 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -98,7 +98,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } -static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, +static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, size_t n, loff_t *ppos) { struct lirc_codec *lirc; @@ -140,10 +140,11 @@ out: } static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, - unsigned long __user arg) + unsigned long arg) { struct lirc_codec *lirc; struct rc_dev *dev; + u32 __user *argp = (u32 __user *)(arg); int ret = 0; __u32 val = 0, tmp; @@ -156,7 +157,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - ret = get_user(val, (__u32 *)arg); + ret = get_user(val, argp); if (ret) return ret; } @@ -265,7 +266,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, } if (_IOC_DIR(cmd) & _IOC_READ) - ret = put_user(val, (__u32 *)arg); + ret = put_user(val, argp); return ret; } -- cgit