| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 1 | /* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol | 
 | 2 |  * | 
 | 3 |  * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com> | 
 | 4 |  * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com> | 
 | 5 |  * | 
 | 6 |  * This program is free software; you can redistribute it and/or modify | 
 | 7 |  *  it under the terms of the GNU General Public License as published by | 
 | 8 |  *  the Free Software Foundation version 2 of the License. | 
 | 9 |  * | 
 | 10 |  *  This program is distributed in the hope that it will be useful, | 
 | 11 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 12 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 13 |  *  GNU General Public License for more details. | 
 | 14 |  */ | 
 | 15 |  | 
 | 16 | /* | 
 | 17 |  * This code handles the 15 bit RC5-ish protocol used by the Streamzap | 
 | 18 |  * PC Remote. | 
 | 19 |  * It considers a carrier of 36 kHz, with a total of 15 bits, where | 
 | 20 |  * the first two bits are start bits, and a third one is a filing bit | 
 | 21 |  */ | 
 | 22 |  | 
| Mauro Carvalho Chehab | f62de67 | 2010-11-09 23:09:57 -0300 | [diff] [blame] | 23 | #include "rc-core-priv.h" | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 24 |  | 
 | 25 | #define RC5_SZ_NBITS		15 | 
 | 26 | #define RC5_UNIT		888888 /* ns */ | 
 | 27 | #define RC5_BIT_START		(1 * RC5_UNIT) | 
 | 28 | #define RC5_BIT_END		(1 * RC5_UNIT) | 
 | 29 |  | 
 | 30 | enum rc5_sz_state { | 
 | 31 | 	STATE_INACTIVE, | 
 | 32 | 	STATE_BIT_START, | 
 | 33 | 	STATE_BIT_END, | 
 | 34 | 	STATE_FINISHED, | 
 | 35 | }; | 
 | 36 |  | 
 | 37 | /** | 
 | 38 |  * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space | 
| David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 39 |  * @dev:	the struct rc_dev descriptor of the device | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 40 |  * @ev:		the struct ir_raw_event descriptor of the pulse/space | 
 | 41 |  * | 
 | 42 |  * This function returns -EINVAL if the pulse violates the state machine | 
 | 43 |  */ | 
| David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 44 | static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 45 | { | 
| David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 46 | 	struct rc5_sz_dec *data = &dev->raw->rc5_sz; | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 47 | 	u8 toggle, command, system; | 
 | 48 | 	u32 scancode; | 
 | 49 |  | 
| Mauro Carvalho Chehab | 52b6614 | 2010-11-17 14:20:52 -0300 | [diff] [blame] | 50 |         if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ)) | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 51 |                 return 0; | 
 | 52 |  | 
| Maxim Levitsky | 4651918 | 2010-10-16 19:56:28 -0300 | [diff] [blame] | 53 | 	if (!is_timing_event(ev)) { | 
 | 54 | 		if (ev.reset) | 
 | 55 | 			data->state = STATE_INACTIVE; | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 56 | 		return 0; | 
 | 57 | 	} | 
 | 58 |  | 
 | 59 | 	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) | 
 | 60 | 		goto out; | 
 | 61 |  | 
 | 62 | again: | 
 | 63 | 	IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", | 
 | 64 | 		   data->state, TO_US(ev.duration), TO_STR(ev.pulse)); | 
 | 65 |  | 
 | 66 | 	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) | 
 | 67 | 		return 0; | 
 | 68 |  | 
 | 69 | 	switch (data->state) { | 
 | 70 |  | 
 | 71 | 	case STATE_INACTIVE: | 
 | 72 | 		if (!ev.pulse) | 
 | 73 | 			break; | 
 | 74 |  | 
 | 75 | 		data->state = STATE_BIT_START; | 
 | 76 | 		data->count = 1; | 
 | 77 | 		data->wanted_bits = RC5_SZ_NBITS; | 
 | 78 | 		decrease_duration(&ev, RC5_BIT_START); | 
 | 79 | 		goto again; | 
 | 80 |  | 
 | 81 | 	case STATE_BIT_START: | 
 | 82 | 		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) | 
 | 83 | 			break; | 
 | 84 |  | 
 | 85 | 		data->bits <<= 1; | 
 | 86 | 		if (!ev.pulse) | 
 | 87 | 			data->bits |= 1; | 
 | 88 | 		data->count++; | 
 | 89 | 		data->state = STATE_BIT_END; | 
 | 90 | 		return 0; | 
 | 91 |  | 
 | 92 | 	case STATE_BIT_END: | 
| David Härdeman | d8b4b58 | 2010-10-29 16:08:23 -0300 | [diff] [blame] | 93 | 		if (!is_transition(&ev, &dev->raw->prev_ev)) | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 94 | 			break; | 
 | 95 |  | 
 | 96 | 		if (data->count == data->wanted_bits) | 
 | 97 | 			data->state = STATE_FINISHED; | 
 | 98 | 		else | 
 | 99 | 			data->state = STATE_BIT_START; | 
 | 100 |  | 
 | 101 | 		decrease_duration(&ev, RC5_BIT_END); | 
 | 102 | 		goto again; | 
 | 103 |  | 
 | 104 | 	case STATE_FINISHED: | 
 | 105 | 		if (ev.pulse) | 
 | 106 | 			break; | 
 | 107 |  | 
 | 108 | 		/* RC5-sz */ | 
 | 109 | 		command  = (data->bits & 0x0003F) >> 0; | 
 | 110 | 		system   = (data->bits & 0x02FC0) >> 6; | 
 | 111 | 		toggle   = (data->bits & 0x01000) ? 1 : 0; | 
 | 112 | 		scancode = system << 6 | command; | 
 | 113 |  | 
 | 114 | 		IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", | 
 | 115 | 			   scancode, toggle); | 
 | 116 |  | 
| Mauro Carvalho Chehab | ca86674 | 2010-11-17 13:53:11 -0300 | [diff] [blame] | 117 | 		rc_keydown(dev, scancode, toggle); | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 118 | 		data->state = STATE_INACTIVE; | 
 | 119 | 		return 0; | 
 | 120 | 	} | 
 | 121 |  | 
 | 122 | out: | 
 | 123 | 	IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", | 
 | 124 | 		   data->state, TO_US(ev.duration), TO_STR(ev.pulse)); | 
 | 125 | 	data->state = STATE_INACTIVE; | 
 | 126 | 	return -EINVAL; | 
 | 127 | } | 
 | 128 |  | 
 | 129 | static struct ir_raw_handler rc5_sz_handler = { | 
| Mauro Carvalho Chehab | 52b6614 | 2010-11-17 14:20:52 -0300 | [diff] [blame] | 130 | 	.protocols	= RC_TYPE_RC5_SZ, | 
| Jarod Wilson | 7a569f5 | 2010-08-07 13:31:40 -0300 | [diff] [blame] | 131 | 	.decode		= ir_rc5_sz_decode, | 
 | 132 | }; | 
 | 133 |  | 
 | 134 | static int __init ir_rc5_sz_decode_init(void) | 
 | 135 | { | 
 | 136 | 	ir_raw_handler_register(&rc5_sz_handler); | 
 | 137 |  | 
 | 138 | 	printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); | 
 | 139 | 	return 0; | 
 | 140 | } | 
 | 141 |  | 
 | 142 | static void __exit ir_rc5_sz_decode_exit(void) | 
 | 143 | { | 
 | 144 | 	ir_raw_handler_unregister(&rc5_sz_handler); | 
 | 145 | } | 
 | 146 |  | 
 | 147 | module_init(ir_rc5_sz_decode_init); | 
 | 148 | module_exit(ir_rc5_sz_decode_exit); | 
 | 149 |  | 
 | 150 | MODULE_LICENSE("GPL"); | 
 | 151 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | 
 | 152 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); | 
 | 153 | MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); |