/**
 * ir_sanyo_decode() - Decode one SANYO pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @duration:	the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
    struct sanyo_dec *data = &dev->raw->sanyo;
    u32 scancode;
    u8 address, command, not_command;

    if (!(dev->raw->enabled_protocols & RC_BIT_SANYO))
        return 0;

    if (!is_timing_event(ev)) {
        if (ev.reset) {
            IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
            data->state = STATE_INACTIVE;
        }
        return 0;
    }

    IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
               data->state, TO_US(ev.duration), TO_STR(ev.pulse));

    switch (data->state) {

    case STATE_INACTIVE:
        if (!ev.pulse)
            break;

        if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
            data->count = 0;
            data->state = STATE_HEADER_SPACE;
            return 0;
        }
        break;


    case STATE_HEADER_SPACE:
        if (ev.pulse)
            break;

        if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
            data->state = STATE_BIT_PULSE;
            return 0;
        }

        break;

    case STATE_BIT_PULSE:
        if (!ev.pulse)
            break;

        if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
            break;

        data->state = STATE_BIT_SPACE;
        return 0;

    case STATE_BIT_SPACE:
        if (ev.pulse)
            break;

        if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
            if (!dev->keypressed) {
                IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
            } else {
                rc_repeat(dev);
                IR_dprintk(1, "SANYO repeat last key\n");
                data->state = STATE_INACTIVE;
            }
            return 0;
        }

        data->bits <<= 1;
        if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
            data->bits |= 1;
        else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
            break;
        data->count++;

        if (data->count == SANYO_NBITS)
            data->state = STATE_TRAILER_PULSE;
        else
            data->state = STATE_BIT_PULSE;

        return 0;

    case STATE_TRAILER_PULSE:
        if (!ev.pulse)
            break;

        if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
            break;

        data->state = STATE_TRAILER_SPACE;
        return 0;

    case STATE_TRAILER_SPACE:
        if (ev.pulse)
            break;

        if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
            break;

        address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
        /* not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; */
        command	    = bitrev8((data->bits >>  8) & 0xff);
        not_command = bitrev8((data->bits >>  0) & 0xff);

        if ((command ^ not_command) != 0xff) {
            IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n",
                       data->bits);
            data->state = STATE_INACTIVE;
            return 0;
        }

        scancode = address << 8 | command;
        IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
        rc_keydown(dev, scancode, 0);
        data->state = STATE_INACTIVE;
        return 0;
    }

    IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
               data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
    data->state = STATE_INACTIVE;
    return -EINVAL;
}
Ejemplo n.º 2
0
/**
 * ir_nec_decode() - Decode one NEC pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
 * @duration:	the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
    struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
    struct nec_dec *data = &ir_dev->raw->nec;
    u32 scancode;
    u8 address, not_address, command, not_command;

    if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
        return 0;

    if (IS_RESET(ev)) {
        data->state = STATE_INACTIVE;
        return 0;
    }

    IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
               data->state, TO_US(ev.duration), TO_STR(ev.pulse));

    switch (data->state) {

    case STATE_INACTIVE:
        if (!ev.pulse)
            break;

        if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
            data->is_nec_x = false;
            data->necx_repeat = false;
        } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
            data->is_nec_x = true;
        else
            break;

        data->count = 0;
        data->state = STATE_HEADER_SPACE;
        return 0;

    case STATE_HEADER_SPACE:
        if (ev.pulse)
            break;

        if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
            data->state = STATE_BIT_PULSE;
            return 0;
        } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
            ir_repeat(input_dev);
            IR_dprintk(1, "Repeat last key\n");
            data->state = STATE_TRAILER_PULSE;
            return 0;
        }

        break;

    case STATE_BIT_PULSE:
        if (!ev.pulse)
            break;

        if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
            break;

        data->state = STATE_BIT_SPACE;
        return 0;

    case STATE_BIT_SPACE:
        if (ev.pulse)
            break;

        if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
                geq_margin(ev.duration,
                           NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
            IR_dprintk(1, "Repeat last key\n");
            ir_repeat(input_dev);
            data->state = STATE_INACTIVE;
            return 0;

        } else if (data->count > NECX_REPEAT_BITS)
            data->necx_repeat = false;

        data->bits <<= 1;
        if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
            data->bits |= 1;
        else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
            break;
        data->count++;

        if (data->count == NEC_NBITS)
            data->state = STATE_TRAILER_PULSE;
        else
            data->state = STATE_BIT_PULSE;

        return 0;

    case STATE_TRAILER_PULSE:
        if (!ev.pulse)
            break;

        if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
            break;

        data->state = STATE_TRAILER_SPACE;
        return 0;

    case STATE_TRAILER_SPACE:
        if (ev.pulse)
            break;

        if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
            break;

        address     = bitrev8((data->bits >> 24) & 0xff);
        not_address = bitrev8((data->bits >> 16) & 0xff);
        command	    = bitrev8((data->bits >>  8) & 0xff);
        not_command = bitrev8((data->bits >>  0) & 0xff);

        if ((command ^ not_command) != 0xff) {
            IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
                       data->bits);
            break;
        }

        if ((address ^ not_address) != 0xff) {
            /* Extended NEC */
            scancode = address     << 16 |
                       not_address <<  8 |
                       command;
            IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
        } else {
            /* Normal NEC */
            scancode = address << 8 | command;
            IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
        }

        if (data->is_nec_x)
            data->necx_repeat = true;

        ir_keydown(input_dev, scancode, 0);
        data->state = STATE_INACTIVE;
        return 0;
    }

    IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
               data->state, TO_US(ev.duration), TO_STR(ev.pulse));
    data->state = STATE_INACTIVE;
    return -EINVAL;
}
Ejemplo n.º 3
0
/**
 * ir_rc6_decode() - Decode one RC6 pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @ev:		the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct rc6_dec *data = &dev->raw->rc6;
	u32 scancode;
	u8 toggle;
	enum rc_proto protocol;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
		goto out;

again:
	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
		return 0;

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		/* Note: larger margin on first pulse since each RC6_UNIT
		   is quite short and some hardware takes some time to
		   adjust to the signal */
		if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
			break;

		data->state = STATE_PREFIX_SPACE;
		data->count = 0;
		return 0;

	case STATE_PREFIX_SPACE:
		if (ev.pulse)
			break;

		if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
			break;

		data->state = STATE_HEADER_BIT_START;
		data->header = 0;
		return 0;

	case STATE_HEADER_BIT_START:
		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
			break;

		data->header <<= 1;
		if (ev.pulse)
			data->header |= 1;
		data->count++;
		data->state = STATE_HEADER_BIT_END;
		return 0;

	case STATE_HEADER_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == RC6_HEADER_NBITS)
			data->state = STATE_TOGGLE_START;
		else
			data->state = STATE_HEADER_BIT_START;

		decrease_duration(&ev, RC6_BIT_END);
		goto again;

	case STATE_TOGGLE_START:
		if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
			break;

		data->toggle = ev.pulse;
		data->state = STATE_TOGGLE_END;
		return 0;

	case STATE_TOGGLE_END:
		if (!is_transition(&ev, &dev->raw->prev_ev) ||
		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
			break;

		if (!(data->header & RC6_STARTBIT_MASK)) {
			IR_dprintk(1, "RC6 invalid start bit\n");
			break;
		}

		data->state = STATE_BODY_BIT_START;
		decrease_duration(&ev, RC6_TOGGLE_END);
		data->count = 0;
		data->body = 0;

		switch (rc6_mode(data)) {
		case RC6_MODE_0:
			data->wanted_bits = RC6_0_NBITS;
			break;
		case RC6_MODE_6A:
			data->wanted_bits = RC6_6A_NBITS;
			break;
		default:
			IR_dprintk(1, "RC6 unknown mode\n");
			goto out;
		}
		goto again;

	case STATE_BODY_BIT_START:
		if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
			/* Discard LSB's that won't fit in data->body */
			if (data->count++ < CHAR_BIT * sizeof data->body) {
				data->body <<= 1;
				if (ev.pulse)
					data->body |= 1;
			}
			data->state = STATE_BODY_BIT_END;
			return 0;
		} else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
				geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
			data->state = STATE_FINISHED;
			goto again;
		}
		break;

	case STATE_BODY_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == data->wanted_bits)
			data->state = STATE_FINISHED;
		else
			data->state = STATE_BODY_BIT_START;

		decrease_duration(&ev, RC6_BIT_END);
		goto again;

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		switch (rc6_mode(data)) {
		case RC6_MODE_0:
			scancode = data->body;
			toggle = data->toggle;
			protocol = RC_PROTO_RC6_0;
			IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
				   scancode, toggle);
			break;

		case RC6_MODE_6A:
			if (data->count > CHAR_BIT * sizeof data->body) {
				IR_dprintk(1, "RC6 too many (%u) data bits\n",
					data->count);
				goto out;
			}

			scancode = data->body;
			switch (data->count) {
			case 20:
				protocol = RC_PROTO_RC6_6A_20;
				toggle = 0;
				break;
			case 24:
				protocol = RC_PROTO_RC6_6A_24;
				toggle = 0;
				break;
			case 32:
				if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
					protocol = RC_PROTO_RC6_MCE;
					toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
					scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
				} else {
					protocol = RC_PROTO_RC6_6A_32;
					toggle = 0;
				}
				break;
			default:
				IR_dprintk(1, "RC6(6A) unsupported length\n");
				goto out;
			}

			IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
				   protocol, scancode, toggle);
			break;
		default:
			IR_dprintk(1, "RC6 unknown mode\n");
			goto out;
		}

		rc_keydown(dev, protocol, scancode, toggle);
		data->state = STATE_INACTIVE;
		return 0;
	}

out:
	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 4
0
    /**
     * ir_rc6_decode() - Decode one RC6 pulse or space
     * @input_dev:	the struct input_dev descriptor of the device
     * @ev:		the struct ir_raw_event descriptor of the pulse/space
     *
     * This function returns -EINVAL if the pulse violates the state machine
     */
    static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
    struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
    struct rc6_dec *data = &ir_dev->raw->rc6;
    u32 scancode;
    u8 toggle;

    if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
        return 0;

    if (IS_RESET(ev)) {
        data->state = STATE_INACTIVE;
        return 0;
    }

    if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
        goto out;

again:
    IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
               data->state, TO_US(ev.duration), TO_STR(ev.pulse));

    if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
        return 0;

    switch (data->state) {

    case STATE_INACTIVE:
        if (!ev.pulse)
            break;

        /* Note: larger margin on first pulse since each RC6_UNIT
           is quite short and some hardware takes some time to
           adjust to the signal */
        if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
            break;

        data->state = STATE_PREFIX_SPACE;
        data->count = 0;
        return 0;

    case STATE_PREFIX_SPACE:
        if (ev.pulse)
            break;

        if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
            break;

        data->state = STATE_HEADER_BIT_START;
        return 0;

    case STATE_HEADER_BIT_START:
        if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
            break;

        data->header <<= 1;
        if (ev.pulse)
            data->header |= 1;
        data->count++;
        data->state = STATE_HEADER_BIT_END;
        return 0;

    case STATE_HEADER_BIT_END:
        if (!is_transition(&ev, &ir_dev->raw->prev_ev))
            break;

        if (data->count == RC6_HEADER_NBITS)
            data->state = STATE_TOGGLE_START;
        else
            data->state = STATE_HEADER_BIT_START;

        decrease_duration(&ev, RC6_BIT_END);
        goto again;

    case STATE_TOGGLE_START:
        if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
            break;

        data->toggle = ev.pulse;
        data->state = STATE_TOGGLE_END;
        return 0;

    case STATE_TOGGLE_END:
        if (!is_transition(&ev, &ir_dev->raw->prev_ev) ||
                !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
            break;

        if (!(data->header & RC6_STARTBIT_MASK)) {
            IR_dprintk(1, "RC6 invalid start bit\n");
            break;
        }

        data->state = STATE_BODY_BIT_START;
        decrease_duration(&ev, RC6_TOGGLE_END);
        data->count = 0;

        switch (rc6_mode(data)) {
        case RC6_MODE_0:
            data->wanted_bits = RC6_0_NBITS;
            break;
        case RC6_MODE_6A:
            /* This might look weird, but we basically
               check the value of the first body bit to
               determine the number of bits in mode 6A */
            if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
                    geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
                data->wanted_bits = RC6_6A_LARGE_NBITS;
            else
                data->wanted_bits = RC6_6A_SMALL_NBITS;
            break;
        default:
            IR_dprintk(1, "RC6 unknown mode\n");
            goto out;
        }
        goto again;

    case STATE_BODY_BIT_START:
        if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
            break;

        data->body <<= 1;
        if (ev.pulse)
            data->body |= 1;
        data->count++;
        data->state = STATE_BODY_BIT_END;
        return 0;

    case STATE_BODY_BIT_END:
        if (!is_transition(&ev, &ir_dev->raw->prev_ev))
            break;

        if (data->count == data->wanted_bits)
            data->state = STATE_FINISHED;
        else
            data->state = STATE_BODY_BIT_START;

        decrease_duration(&ev, RC6_BIT_END);
        goto again;

    case STATE_FINISHED:
        if (ev.pulse)
            break;

        switch (rc6_mode(data)) {
        case RC6_MODE_0:
            scancode = data->body & 0xffff;
            toggle = data->toggle;
            IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
                       scancode, toggle);
            break;
        case RC6_MODE_6A:
            if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
                toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
                scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
            } else {
                toggle = 0;
                scancode = data->body & 0xffffff;
            }

            IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
                       scancode, toggle);
            break;
        default:
            IR_dprintk(1, "RC6 unknown mode\n");
            goto out;
        }

        ir_keydown(input_dev, scancode, toggle);
        data->state = STATE_INACTIVE;
        return 0;
    }

out:
    IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
               data->state, TO_US(ev.duration), TO_STR(ev.pulse));
    data->state = STATE_INACTIVE;
    return -EINVAL;
}
Ejemplo n.º 5
0
/**
 * ir_rc5_decode() - Decode one RC-5 pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @ev:		the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct rc5_dec *data = &dev->raw->rc5;
	u8 toggle;
	u32 scancode;

        if (!(dev->raw->enabled_protocols & RC_TYPE_RC5))
                return 0;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		goto out;

again:
	IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		return 0;

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		data->state = STATE_BIT_START;
		data->count = 1;
		/* We just need enough bits to get to STATE_CHECK_RC5X */
		data->wanted_bits = RC5X_NBITS;
		decrease_duration(&ev, RC5_BIT_START);
		goto again;

	case STATE_BIT_START:
		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
			break;

		data->bits <<= 1;
		if (!ev.pulse)
			data->bits |= 1;
		data->count++;
		data->state = STATE_BIT_END;
		return 0;

	case STATE_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == data->wanted_bits)
			data->state = STATE_FINISHED;
		else if (data->count == CHECK_RC5X_NBITS)
			data->state = STATE_CHECK_RC5X;
		else
			data->state = STATE_BIT_START;

		decrease_duration(&ev, RC5_BIT_END);
		goto again;

	case STATE_CHECK_RC5X:
		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
			/* RC5X */
			data->wanted_bits = RC5X_NBITS;
			decrease_duration(&ev, RC5X_SPACE);
		} else {
			/* RC5 */
			data->wanted_bits = RC5_NBITS;
		}
		data->state = STATE_BIT_START;
		goto again;

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		if (data->wanted_bits == RC5X_NBITS) {
			/* RC5X */
			u8 xdata, command, system;
			xdata    = (data->bits & 0x0003F) >> 0;
			command  = (data->bits & 0x00FC0) >> 6;
			system   = (data->bits & 0x1F000) >> 12;
			toggle   = (data->bits & 0x20000) ? 1 : 0;
			command += (data->bits & 0x01000) ? 0 : 0x40;
			scancode = system << 16 | command << 8 | xdata;

			IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
				   scancode, toggle);

		} else {
Ejemplo n.º 6
0
/**
 * ir_rc5_decode() - Decode one RC-5 pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @ev:		the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct rc5_dec *data = &dev->raw->rc5;
	u8 toggle;
	u32 scancode;
	enum rc_type protocol;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		goto out;

again:
	IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		return 0;

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		data->state = STATE_BIT_START;
		data->count = 1;
		decrease_duration(&ev, RC5_BIT_START);
		goto again;

	case STATE_BIT_START:
		if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
			data->state = STATE_FINISHED;
			goto again;
		}

		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
			break;

		data->bits <<= 1;
		if (!ev.pulse)
			data->bits |= 1;
		data->count++;
		data->state = STATE_BIT_END;
		return 0;

	case STATE_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == CHECK_RC5X_NBITS)
			data->state = STATE_CHECK_RC5X;
		else
			data->state = STATE_BIT_START;

		decrease_duration(&ev, RC5_BIT_END);
		goto again;

	case STATE_CHECK_RC5X:
		if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
			data->is_rc5x = true;
			decrease_duration(&ev, RC5X_SPACE);
		} else
			data->is_rc5x = false;
		data->state = STATE_BIT_START;
		goto again;

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		if (data->is_rc5x && data->count == RC5X_NBITS) {
			/* RC5X */
			u8 xdata, command, system;
			if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
				data->state = STATE_INACTIVE;
				return 0;
			}
			xdata    = (data->bits & 0x0003F) >> 0;
			command  = (data->bits & 0x00FC0) >> 6;
			system   = (data->bits & 0x1F000) >> 12;
			toggle   = (data->bits & 0x20000) ? 1 : 0;
			command += (data->bits & 0x01000) ? 0 : 0x40;
			scancode = system << 16 | command << 8 | xdata;
			protocol = RC_TYPE_RC5X;

		} else if (!data->is_rc5x && data->count == RC5_NBITS) {
Ejemplo n.º 7
0
/**
 * ir_sony_decode() - Decode one Sony pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
 * @ev:         the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct sony_dec *data = &ir_dev->raw->sony;
	u32 scancode;
	u8 device, subdevice, function;

	if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
		return 0;

	if (IS_RESET(ev)) {
		data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
		goto out;

	IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
			break;

		data->count = 0;
		data->state = STATE_HEADER_SPACE;
		return 0;

	case STATE_HEADER_SPACE:
		if (ev.pulse)
			break;

		if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
			break;

		data->state = STATE_BIT_PULSE;
		return 0;

	case STATE_BIT_PULSE:
		if (!ev.pulse)
			break;

		data->bits <<= 1;
		if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
			data->bits |= 1;
		else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
			break;

		data->count++;
		data->state = STATE_BIT_SPACE;
		return 0;

	case STATE_BIT_SPACE:
		if (ev.pulse)
			break;

		if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
			break;

		decrease_duration(&ev, SONY_BIT_SPACE);

		if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
			data->state = STATE_BIT_PULSE;
			return 0;
		}

		data->state = STATE_FINISHED;
		/* Fall through */

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
			break;

		switch (data->count) {
		case 12:
			device    = bitrev8((data->bits <<  3) & 0xF8);
			subdevice = 0;
			function  = bitrev8((data->bits >>  4) & 0xFE);
			break;
		case 15:
			device    = bitrev8((data->bits >>  0) & 0xFF);
			subdevice = 0;
			function  = bitrev8((data->bits >>  7) & 0xFD);
			break;
		case 20:
			device    = bitrev8((data->bits >>  5) & 0xF8);
			subdevice = bitrev8((data->bits >>  0) & 0xFF);
			function  = bitrev8((data->bits >> 12) & 0xFE);
			break;
		default:
			IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
			goto out;
		}

		scancode = device << 16 | subdevice << 8 | function;
		IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
		ir_keydown(input_dev, scancode, 0);
		data->state = STATE_INACTIVE;
		return 0;
	}

out:
	IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 8
0
static int ir_rc6_decode(struct rc6_ir *data, struct ir_signal signal,
		struct ir_protocol *ip)
{
	int i;
	i = ip->priv;
	if (i >= MAX_RC6_INFR_NR)
		goto out;

	if (!geq_margin(signal.duration, RC6_UNIT, RC6_UNIT / 2))
		goto out;
		
again:
	hiir_debug("RC6 decode started at state %i (%uus %s) "
		"count %d header 0x%x bits 0x%llx, count:%d\n",
		data->state, signal.duration, TO_STR(signal.pulse),
		data->count, data->header, data->bits, data->count);

	if (!geq_margin(signal.duration, RC6_UNIT, RC6_UNIT / 2))
		return 0;

	switch (data->state) {
	case STATE_INACTIVE:
		if (!signal.pulse)
			break;

		if (!eq_margin(signal.duration, RC6_PREFIX_PULSE, RC6_UNIT))
			break;

		data->state = STATE_PREFIX_SPACE;
		data->bits = 0;
		data->count = 0;
		data->header = 0;
		memset(&data->this_key, 0, sizeof(struct key_attr));
		return 0;

	case STATE_PREFIX_SPACE:
		if (signal.pulse)
			break;

		if (!eq_margin(signal.duration, RC6_PREFIX_SPACE,
			RC6_UNIT / 2))
			break;

		data->state = STATE_HEADER_BIT_START;
		return 0;

	case STATE_HEADER_BIT_START:
		if (!eq_margin(signal.duration, RC6_BIT_START,
			RC6_UNIT / 2))
			break;

		data->header <<= 1;
		if (signal.pulse)
			data->header |= 1;

		data->count++;
		data->state = STATE_HEADER_BIT_END;
		return 0;

	case STATE_HEADER_BIT_END:
		if (!is_transition(&signal, &data->prev_signal))
			break;

		if (data->count == RC6_HEADER_NBITS)
			data->state = STATE_TOGGLE_START;
		else
			data->state = STATE_HEADER_BIT_START;

		decrease_duration(&signal, RC6_BIT_END);
		goto again;

	case STATE_TOGGLE_START:
		if (!eq_margin(signal.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
			break;

		data->state = STATE_TOGGLE_END;
		return 0;

	case STATE_TOGGLE_END:
		if (!is_transition(&signal, &data->prev_signal) 
			|| !geq_margin(signal.duration, RC6_TOGGLE_END,
				RC6_UNIT / 2))
			break;

		data->state = STATE_BIT_START;
		decrease_duration(&signal, RC6_TOGGLE_END);
		data->count = 0;

		goto again;

	case STATE_BIT_START:
		if (!eq_margin(signal.duration, RC6_BIT_START, RC6_UNIT / 2))
			break;
		
		data->bits <<= 1;
		if (signal.pulse)
			data->bits |= 1;
		data->count++;
		data->state = STATE_BIT_END;
		return 0;

	case STATE_BIT_END:
		if (!is_transition(&signal, &data->prev_signal))
			break;

		if (data->count == ip->attr.wanna_bits) {
			data->scancode = data->bits;
			data->this_key.lower = (data->scancode & (~RC6_TOGGLE_MASK));
			data->this_key.upper = 0;
			data->state = STATE_FINISHED;
			return 0;
		} else
			data->state = STATE_BIT_START;

		decrease_duration(&signal, RC6_BIT_END);
		goto again;

	case STATE_FINISHED:
		if (signal.pulse)
			break;

		data->state = STATE_INACTIVE;
		return 0;
	}

out:
	hiir_info("RC6 decode failed at state %i (%uus %s), bits received:%d\n",
		   data->state, signal.duration, TO_STR(signal.pulse), data->count);
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 9
0
/**
 * ir_nec_decode() - Decode one NEC pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @duration:	the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct nec_dec *data = &dev->raw->nec;
	u32 scancode;
	u8 address, not_address, command, not_command;
	bool send_32bits = false;

	if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
		return 0;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
			data->is_nec_x = false;
			data->necx_repeat = false;
		} else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
			data->is_nec_x = true;
		else
			break;

		data->count = 0;
		data->state = STATE_HEADER_SPACE;
		return 0;

	case STATE_HEADER_SPACE:
		if (ev.pulse)
			break;

		if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
			data->state = STATE_BIT_PULSE;
			return 0;
		} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
			if (!dev->keypressed) {
				IR_dprintk(1, "Discarding last key repeat: event after key up\n");
			} else {
				rc_repeat(dev);
				IR_dprintk(1, "Repeat last key\n");
				data->state = STATE_TRAILER_PULSE;
			}
			return 0;
		}

		break;

	case STATE_BIT_PULSE:
		if (!ev.pulse)
			break;

		if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
			break;

		data->state = STATE_BIT_SPACE;
		return 0;

	case STATE_BIT_SPACE:
		if (ev.pulse)
			break;

		if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
			geq_margin(ev.duration,
			NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
				IR_dprintk(1, "Repeat last key\n");
				rc_repeat(dev);
				data->state = STATE_INACTIVE;
				return 0;

		} else if (data->count > NECX_REPEAT_BITS)
			data->necx_repeat = false;

		data->bits <<= 1;
		if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
			data->bits |= 1;
		else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
			break;
		data->count++;

		if (data->count == NEC_NBITS)
			data->state = STATE_TRAILER_PULSE;
		else
			data->state = STATE_BIT_PULSE;

		return 0;

	case STATE_TRAILER_PULSE:
		if (!ev.pulse)
			break;

		if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
			break;

		data->state = STATE_TRAILER_SPACE;
		return 0;

	case STATE_TRAILER_SPACE:
		if (ev.pulse)
			break;

		if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
			break;

		address     = bitrev8((data->bits >> 24) & 0xff);
		not_address = bitrev8((data->bits >> 16) & 0xff);
		command	    = bitrev8((data->bits >>  8) & 0xff);
		not_command = bitrev8((data->bits >>  0) & 0xff);

		if ((command ^ not_command) != 0xff) {
			IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
				   data->bits);
			send_32bits = true;
		}

		if (send_32bits) {
			/* NEC transport, but modified protocol, used by at
			 * least Apple and TiVo remotes */
			scancode = data->bits;
			IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
		} else if ((address ^ not_address) != 0xff) {
			/* Extended NEC */
			scancode = address     << 16 |
				   not_address <<  8 |
				   command;
			IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
		} else {
			/* Normal NEC */
			scancode = address << 8 | command;
			IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
		}

		if (data->is_nec_x)
			data->necx_repeat = true;

		rc_keydown(dev, scancode, 0);
		data->state = STATE_INACTIVE;
		return 0;
	}

	IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 10
0
/**
 * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
 * @input_dev:	the struct input_dev descriptor of the device
 * @ev:		the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
	struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
	u8 toggle, command, system;
	u32 scancode;

        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
                return 0;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		goto out;

again:
	IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
		return 0;

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		data->state = STATE_BIT_START;
		data->count = 1;
		data->wanted_bits = RC5_SZ_NBITS;
		decrease_duration(&ev, RC5_BIT_START);
		goto again;

	case STATE_BIT_START:
		if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
			break;

		data->bits <<= 1;
		if (!ev.pulse)
			data->bits |= 1;
		data->count++;
		data->state = STATE_BIT_END;
		return 0;

	case STATE_BIT_END:
		if (!is_transition(&ev, &ir_dev->raw->prev_ev))
			break;

		if (data->count == data->wanted_bits)
			data->state = STATE_FINISHED;
		else
			data->state = STATE_BIT_START;

		decrease_duration(&ev, RC5_BIT_END);
		goto again;

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		/* RC5-sz */
		command  = (data->bits & 0x0003F) >> 0;
		system   = (data->bits & 0x02FC0) >> 6;
		toggle   = (data->bits & 0x01000) ? 1 : 0;
		scancode = system << 6 | command;

		IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
			   scancode, toggle);

		ir_keydown(input_dev, scancode, toggle);
		data->state = STATE_INACTIVE;
		return 0;
	}

out:
	IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 11
0
static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct rc6_dec *data = &dev->raw->rc6;
	u32 scancode;
	u8 toggle;

	if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
		return 0;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
		goto out;

again:
	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));

	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
		return 0;

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
			break;

		data->state = STATE_PREFIX_SPACE;
		data->count = 0;
		return 0;

	case STATE_PREFIX_SPACE:
		if (ev.pulse)
			break;

		if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
			break;

		data->state = STATE_HEADER_BIT_START;
		data->header = 0;
		return 0;

	case STATE_HEADER_BIT_START:
		if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
			break;

		data->header <<= 1;
		if (ev.pulse)
			data->header |= 1;
		data->count++;
		data->state = STATE_HEADER_BIT_END;
		return 0;

	case STATE_HEADER_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == RC6_HEADER_NBITS)
			data->state = STATE_TOGGLE_START;
		else
			data->state = STATE_HEADER_BIT_START;

		decrease_duration(&ev, RC6_BIT_END);
		goto again;

	case STATE_TOGGLE_START:
		if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
			break;

		data->toggle = ev.pulse;
		data->state = STATE_TOGGLE_END;
		return 0;

	case STATE_TOGGLE_END:
		if (!is_transition(&ev, &dev->raw->prev_ev) ||
		    !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
			break;

		if (!(data->header & RC6_STARTBIT_MASK)) {
			IR_dprintk(1, "RC6 invalid start bit\n");
			break;
		}

		data->state = STATE_BODY_BIT_START;
		decrease_duration(&ev, RC6_TOGGLE_END);
		data->count = 0;
		data->body = 0;

		switch (rc6_mode(data)) {
		case RC6_MODE_0:
			data->wanted_bits = RC6_0_NBITS;
			break;
		case RC6_MODE_6A:
			data->wanted_bits = RC6_6A_NBITS;
			break;
		default:
			IR_dprintk(1, "RC6 unknown mode\n");
			goto out;
		}
		goto again;

	case STATE_BODY_BIT_START:
		if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
			
			if (data->count++ < CHAR_BIT * sizeof data->body) {
				data->body <<= 1;
				if (ev.pulse)
					data->body |= 1;
			}
			data->state = STATE_BODY_BIT_END;
			return 0;
		} else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
				geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
			data->state = STATE_FINISHED;
			goto again;
		}
		break;

	case STATE_BODY_BIT_END:
		if (!is_transition(&ev, &dev->raw->prev_ev))
			break;

		if (data->count == data->wanted_bits)
			data->state = STATE_FINISHED;
		else
			data->state = STATE_BODY_BIT_START;

		decrease_duration(&ev, RC6_BIT_END);
		goto again;

	case STATE_FINISHED:
		if (ev.pulse)
			break;

		switch (rc6_mode(data)) {
		case RC6_MODE_0:
			scancode = data->body;
			toggle = data->toggle;
			IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
				   scancode, toggle);
			break;
		case RC6_MODE_6A:
			if (data->count > CHAR_BIT * sizeof data->body) {
				IR_dprintk(1, "RC6 too many (%u) data bits\n",
					data->count);
				goto out;
			}

			scancode = data->body;
			if (data->count == RC6_6A_32_NBITS &&
					(scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
				
				toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
				scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
			} else {
				toggle = 0;
			}
			IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
				   scancode, toggle);
			break;
		default:
			IR_dprintk(1, "RC6 unknown mode\n");
			goto out;
		}

		rc_keydown(dev, scancode, toggle);
		data->state = STATE_INACTIVE;
		return 0;
	}

out:
	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}
Ejemplo n.º 12
0
/**
 * ir_xmp_decode() - Decode one XMP pulse or space
 * @dev:	the struct rc_dev descriptor of the device
 * @duration:	the struct ir_raw_event descriptor of the pulse/space
 *
 * This function returns -EINVAL if the pulse violates the state machine
 */
static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
	struct xmp_dec *data = &dev->raw->xmp;

	if (!(dev->enabled_protocols & RC_BIT_XMP))
		return 0;

	if (!is_timing_event(ev)) {
		if (ev.reset)
			data->state = STATE_INACTIVE;
		return 0;
	}

	IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n",
		   data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));

	switch (data->state) {

	case STATE_INACTIVE:
		if (!ev.pulse)
			break;

		if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2)) {
			data->count = 0;
			data->state = STATE_NIBBLE_SPACE;
		}

		return 0;

	case STATE_LEADER_PULSE:
		if (!ev.pulse)
			break;

		if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2))
			data->state = STATE_NIBBLE_SPACE;

		return 0;

	case STATE_NIBBLE_SPACE:
		if (ev.pulse)
			break;

		if (geq_margin(ev.duration, XMP_TRAILER_SPACE, XMP_NIBBLE_PREFIX)) {
			int divider, i;
			u8 addr, subaddr, subaddr2, toggle, oem, obc1, obc2, sum1, sum2;
			u32 *n;
			u32 scancode;

			if (data->count != 16) {
				IR_dprintk(2, "received TRAILER period at index %d: %u\n",
					data->count, ev.duration);
				data->state = STATE_INACTIVE;
				return -EINVAL;
			}

			n = data->durations;
			/*
			 * the 4th nibble should be 15 so base the divider on this
			 * to transform durations into nibbles. Substract 2000 from
			 * the divider to compensate for fluctuations in the signal
			 */
			divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000;
			if (divider < 50) {
				IR_dprintk(2, "divider to small %d.\n", divider);
				data->state = STATE_INACTIVE;
				return -EINVAL;
			}

			/* convert to nibbles and do some sanity checks */
			for (i = 0; i < 16; i++)
				n[i] = (n[i] - XMP_NIBBLE_PREFIX) / divider;
			sum1 = (15 + n[0] + n[1] + n[2] + n[3] +
				n[4] + n[5] + n[6] + n[7]) % 16;
			sum2 = (15 + n[8] + n[9] + n[10] + n[11] +
				n[12] + n[13] + n[14] + n[15]) % 16;

			if (sum1 != 15 || sum2 != 15) {
				IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n",
					sum1, sum2);
				data->state = STATE_INACTIVE;
				return -EINVAL;
			}

			subaddr  = n[0] << 4 | n[2];
			subaddr2 = n[8] << 4 | n[11];
			oem      = n[4] << 4 | n[5];
			addr     = n[6] << 4 | n[7];
			toggle   = n[10];
			obc1 = n[12] << 4 | n[13];
			obc2 = n[14] << 4 | n[15];
			if (subaddr != subaddr2) {
				IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
					subaddr, subaddr2);
				data->state = STATE_INACTIVE;
				return -EINVAL;
			}
			if (oem != 0x44)
				IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
					oem);

			scancode = addr << 24 | subaddr << 16 |
				   obc1 << 8 | obc2;
			IR_dprintk(1, "XMP scancode 0x%06x\n", scancode);

			if (toggle == 0) {
				rc_keydown(dev, RC_TYPE_XMP, scancode, 0);
			} else {
				rc_repeat(dev);
				IR_dprintk(1, "Repeat last key\n");
			}
			data->state = STATE_INACTIVE;

			return 0;

		} else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) {
			/* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */
			if (data->count == 16) {
				IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
					data->count, ev.duration);
				/*
				 * TODO: for now go back to half frame position
				 *	 so trailer can be found and key press
				 *	 can be handled.
				 */
				data->count = 8;
			}

			else if (data->count != 8)
				IR_dprintk(2, "received half frame pulse at index %d: %u\n",
					data->count, ev.duration);
			data->state = STATE_LEADER_PULSE;

			return 0;

		} else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) {
			/* store nibble raw data, decode after trailer */
			if (data->count == 16) {
				IR_dprintk(2, "to many pulses (%d) ignoring: %u\n",
					data->count, ev.duration);
				data->state = STATE_INACTIVE;
				return -EINVAL;
			}
			data->durations[data->count] = ev.duration;
			data->count++;
			data->state = STATE_LEADER_PULSE;

			return 0;

		}

		break;
	}

	IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n",
		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
	data->state = STATE_INACTIVE;
	return -EINVAL;
}