diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-22 00:35:44 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-22 18:05:37 -0400 |
commit | 39dc5c3adf65bf86115aeccd740993256e6a22d4 (patch) | |
tree | f8f523805bb658cb84b55d9e2d925685628bc04e /drivers/media/IR/mceusb.c | |
parent | 4c8fa38198e58e9ccf5fca1d76792540eac047da (diff) |
[media] mceusb: improve ir data buffer parser
Switch to a state machine that properly handles all incoming urb data
packets, and reads much cleaner and corrects some minor parsing errors
that were hindering decode on cx231xx/Polaris integrated IR. Also tested
with four different mceusb variants, and works perfectly with all of
them (at least for the rc6a mce remotes).
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Diffstat (limited to 'drivers/media/IR/mceusb.c')
-rw-r--r-- | drivers/media/IR/mceusb.c | 151 |
1 files changed, 103 insertions, 48 deletions
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c index a726f63ecfea..c890cd521b20 100644 --- a/drivers/media/IR/mceusb.c +++ b/drivers/media/IR/mceusb.c | |||
@@ -56,14 +56,16 @@ | |||
56 | #define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ | 56 | #define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ |
57 | #define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ | 57 | #define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ |
58 | #define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ | 58 | #define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ |
59 | #define MCE_CONTROL_HEADER 0x9F /* MCE status header */ | 59 | #define MCE_CONTROL_HEADER 0x9f /* MCE status header */ |
60 | #define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ | 60 | #define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ |
61 | #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ | 61 | #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ |
62 | #define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ | 62 | #define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ |
63 | #define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ | 63 | #define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ |
64 | #define MCE_PULSE_MASK 0x7F /* Pulse mask */ | 64 | #define MCE_PULSE_MASK 0x7f /* Pulse mask */ |
65 | #define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */ | 65 | #define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */ |
66 | #define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */ | 66 | #define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */ |
67 | #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ | ||
68 | #define MCE_COMMAND_IRDATA 0x80 /* buf & MCE_COMMAND_MASK == 0x80 -> IR data */ | ||
67 | 69 | ||
68 | 70 | ||
69 | /* module parameters */ | 71 | /* module parameters */ |
@@ -256,8 +258,15 @@ struct mceusb_dev { | |||
256 | /* buffers and dma */ | 258 | /* buffers and dma */ |
257 | unsigned char *buf_in; | 259 | unsigned char *buf_in; |
258 | unsigned int len_in; | 260 | unsigned int len_in; |
259 | u8 cmd; /* MCE command type */ | 261 | |
260 | u8 rem; /* Remaining IR data bytes in packet */ | 262 | enum { |
263 | CMD_HEADER = 0, | ||
264 | SUBCMD, | ||
265 | CMD_DATA, | ||
266 | PARSE_IRDATA, | ||
267 | } parser_state; | ||
268 | u8 cmd, rem; /* Remaining IR data bytes in packet */ | ||
269 | |||
261 | dma_addr_t dma_in; | 270 | dma_addr_t dma_in; |
262 | dma_addr_t dma_out; | 271 | dma_addr_t dma_out; |
263 | 272 | ||
@@ -302,19 +311,51 @@ struct mceusb_dev { | |||
302 | static char DEVICE_RESET[] = {0x00, 0xff, 0xaa}; | 311 | static char DEVICE_RESET[] = {0x00, 0xff, 0xaa}; |
303 | static char GET_REVISION[] = {0xff, 0x0b}; | 312 | static char GET_REVISION[] = {0xff, 0x0b}; |
304 | static char GET_UNKNOWN[] = {0xff, 0x18}; | 313 | static char GET_UNKNOWN[] = {0xff, 0x18}; |
305 | static char GET_UNKNOWN2[] = {0x9f, 0x05}; | 314 | static char GET_UNKNOWN2[] = {MCE_CONTROL_HEADER, 0x05}; |
306 | static char GET_CARRIER_FREQ[] = {0x9f, 0x07}; | 315 | static char GET_CARRIER_FREQ[] = {MCE_CONTROL_HEADER, 0x07}; |
307 | static char GET_RX_TIMEOUT[] = {0x9f, 0x0d}; | 316 | static char GET_RX_TIMEOUT[] = {MCE_CONTROL_HEADER, 0x0d}; |
308 | static char GET_TX_BITMASK[] = {0x9f, 0x13}; | 317 | static char GET_TX_BITMASK[] = {MCE_CONTROL_HEADER, 0x13}; |
309 | static char GET_RX_SENSOR[] = {0x9f, 0x15}; | 318 | static char GET_RX_SENSOR[] = {MCE_CONTROL_HEADER, 0x15}; |
310 | /* sub in desired values in lower byte or bytes for full command */ | 319 | /* sub in desired values in lower byte or bytes for full command */ |
311 | /* FIXME: make use of these for transmit. | 320 | /* FIXME: make use of these for transmit. |
312 | static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00}; | 321 | static char SET_CARRIER_FREQ[] = {MCE_CONTROL_HEADER, 0x06, 0x00, 0x00}; |
313 | static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00}; | 322 | static char SET_TX_BITMASK[] = {MCE_CONTROL_HEADER, 0x08, 0x00}; |
314 | static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00}; | 323 | static char SET_RX_TIMEOUT[] = {MCE_CONTROL_HEADER, 0x0c, 0x00, 0x00}; |
315 | static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00}; | 324 | static char SET_RX_SENSOR[] = {MCE_CONTROL_HEADER, 0x14, 0x00}; |
316 | */ | 325 | */ |
317 | 326 | ||
327 | static int mceusb_cmdsize(u8 cmd, u8 subcmd) | ||
328 | { | ||
329 | int datasize = 0; | ||
330 | |||
331 | switch (cmd) { | ||
332 | case 0x00: | ||
333 | if (subcmd == 0xff) | ||
334 | datasize = 1; | ||
335 | break; | ||
336 | case 0xff: | ||
337 | switch (subcmd) { | ||
338 | case 0x0b: | ||
339 | datasize = 2; | ||
340 | break; | ||
341 | } | ||
342 | case MCE_CONTROL_HEADER: | ||
343 | switch (subcmd) { | ||
344 | case 0x04: | ||
345 | case 0x06: | ||
346 | case 0x0c: | ||
347 | case 0x15: | ||
348 | datasize = 2; | ||
349 | break; | ||
350 | case 0x08: | ||
351 | case 0x14: | ||
352 | datasize = 1; | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | return datasize; | ||
357 | } | ||
358 | |||
318 | static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, | 359 | static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, |
319 | int len, bool out) | 360 | int len, bool out) |
320 | { | 361 | { |
@@ -380,7 +421,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, | |||
380 | break; | 421 | break; |
381 | } | 422 | } |
382 | break; | 423 | break; |
383 | case 0x9f: | 424 | case MCE_CONTROL_HEADER: |
384 | switch (subcmd) { | 425 | switch (subcmd) { |
385 | case 0x03: | 426 | case 0x03: |
386 | dev_info(dev, "Ping\n"); | 427 | dev_info(dev, "Ping\n"); |
@@ -629,7 +670,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
629 | struct mceusb_dev *ir = priv; | 670 | struct mceusb_dev *ir = priv; |
630 | int clk = 10000000; | 671 | int clk = 10000000; |
631 | int prescaler = 0, divisor = 0; | 672 | int prescaler = 0, divisor = 0; |
632 | unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 }; | 673 | unsigned char cmdbuf[4] = { MCE_CONTROL_HEADER, 0x06, 0x00, 0x00 }; |
633 | 674 | ||
634 | /* Carrier has changed */ | 675 | /* Carrier has changed */ |
635 | if (ir->carrier != carrier) { | 676 | if (ir->carrier != carrier) { |
@@ -669,46 +710,33 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
669 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) | 710 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) |
670 | { | 711 | { |
671 | DEFINE_IR_RAW_EVENT(rawir); | 712 | DEFINE_IR_RAW_EVENT(rawir); |
672 | int i, start_index = 0; | 713 | int i = 0; |
673 | u8 hdr = MCE_CONTROL_HEADER; | ||
674 | 714 | ||
675 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ | 715 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ |
676 | if (ir->flags.microsoft_gen1) | 716 | if (ir->flags.microsoft_gen1) |
677 | start_index = 2; | 717 | i = 2; |
678 | |||
679 | for (i = start_index; i < buf_len;) { | ||
680 | if (ir->rem == 0) { | ||
681 | /* decode mce packets of the form (84),AA,BB,CC,DD */ | ||
682 | /* IR data packets can span USB messages - rem */ | ||
683 | hdr = ir->buf_in[i]; | ||
684 | ir->rem = (hdr & MCE_PACKET_LENGTH_MASK); | ||
685 | ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK); | ||
686 | dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n", | ||
687 | ir->rem, ir->cmd); | ||
688 | i++; | ||
689 | } | ||
690 | 718 | ||
691 | /* don't process MCE commands */ | 719 | for (; i < buf_len; i++) { |
692 | if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) { | 720 | switch (ir->parser_state) { |
693 | ir->rem = 0; | 721 | case SUBCMD: |
694 | return; | 722 | ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); |
695 | } | 723 | ir->parser_state = CMD_DATA; |
696 | 724 | break; | |
697 | for (; (ir->rem > 0) && (i < buf_len); i++) { | 725 | case PARSE_IRDATA: |
698 | ir->rem--; | 726 | ir->rem--; |
699 | |||
700 | rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); | 727 | rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); |
701 | rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) | 728 | rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) |
702 | * MCE_TIME_UNIT * 1000; | 729 | * MCE_TIME_UNIT * 1000; |
703 | 730 | ||
704 | if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { | 731 | if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { |
705 | if (ir->rawir.pulse == rawir.pulse) | 732 | if (ir->rawir.pulse == rawir.pulse) { |
706 | ir->rawir.duration += rawir.duration; | 733 | ir->rawir.duration += rawir.duration; |
707 | else { | 734 | } else { |
708 | ir->rawir.duration = rawir.duration; | 735 | ir->rawir.duration = rawir.duration; |
709 | ir->rawir.pulse = rawir.pulse; | 736 | ir->rawir.pulse = rawir.pulse; |
710 | } | 737 | } |
711 | continue; | 738 | if (ir->rem) |
739 | break; | ||
712 | } | 740 | } |
713 | rawir.duration += ir->rawir.duration; | 741 | rawir.duration += ir->rawir.duration; |
714 | ir->rawir.duration = 0; | 742 | ir->rawir.duration = 0; |
@@ -719,14 +747,40 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) | |||
719 | rawir.duration); | 747 | rawir.duration); |
720 | 748 | ||
721 | ir_raw_event_store(ir->idev, &rawir); | 749 | ir_raw_event_store(ir->idev, &rawir); |
750 | break; | ||
751 | case CMD_DATA: | ||
752 | ir->rem--; | ||
753 | break; | ||
754 | case CMD_HEADER: | ||
755 | /* decode mce packets of the form (84),AA,BB,CC,DD */ | ||
756 | /* IR data packets can span USB messages - rem */ | ||
757 | ir->cmd = ir->buf_in[i]; | ||
758 | if ((ir->cmd == MCE_CONTROL_HEADER) || | ||
759 | ((ir->cmd & MCE_COMMAND_MASK) != MCE_COMMAND_IRDATA)) { | ||
760 | ir->parser_state = SUBCMD; | ||
761 | continue; | ||
762 | } | ||
763 | ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); | ||
764 | dev_dbg(ir->dev, "Processing RX data: len = %d\n", | ||
765 | ir->rem); | ||
766 | if (ir->rem) { | ||
767 | ir->parser_state = PARSE_IRDATA; | ||
768 | break; | ||
769 | } | ||
770 | /* | ||
771 | * a package with len=0 (e. g. 0x80) means end of | ||
772 | * data. We could use it to do the call to | ||
773 | * ir_raw_event_handle(). For now, we don't need to | ||
774 | * use it. | ||
775 | */ | ||
776 | break; | ||
722 | } | 777 | } |
723 | 778 | ||
724 | if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f) | 779 | if (ir->parser_state != CMD_HEADER && !ir->rem) |
725 | ir->rem = 0; | 780 | ir->parser_state = CMD_HEADER; |
726 | |||
727 | dev_dbg(ir->dev, "calling ir_raw_event_handle\n"); | ||
728 | ir_raw_event_handle(ir->idev); | ||
729 | } | 781 | } |
782 | dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); | ||
783 | ir_raw_event_handle(ir->idev); | ||
730 | } | 784 | } |
731 | 785 | ||
732 | static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) | 786 | static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) |
@@ -768,6 +822,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) | |||
768 | 822 | ||
769 | case -EPIPE: | 823 | case -EPIPE: |
770 | default: | 824 | default: |
825 | dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); | ||
771 | break; | 826 | break; |
772 | } | 827 | } |
773 | 828 | ||