static int udraw_raw_event()

in hid-udraw-ps3.c [101:262]


static int udraw_raw_event(struct hid_device *hdev, struct hid_report *report,
	 u8 *data, int len)
{
	struct udraw *udraw = hid_get_drvdata(hdev);
	int touch;
	int x, y, z;

	if (len != 27)
		return 0;

	if (data[11] == 0x00)
		touch = TOUCH_NONE;
	else if (data[11] == 0x40)
		touch = TOUCH_PEN;
	else if (data[11] == 0x80)
		touch = TOUCH_FINGER;
	else
		touch = TOUCH_TWOFINGER;

	/* joypad */
	input_report_key(udraw->joy_input_dev, BTN_WEST, data[0] & 1);
	input_report_key(udraw->joy_input_dev, BTN_SOUTH, !!(data[0] & 2));
	input_report_key(udraw->joy_input_dev, BTN_EAST, !!(data[0] & 4));
	input_report_key(udraw->joy_input_dev, BTN_NORTH, !!(data[0] & 8));

	input_report_key(udraw->joy_input_dev, BTN_SELECT, !!(data[1] & 1));
	input_report_key(udraw->joy_input_dev, BTN_START, !!(data[1] & 2));
	input_report_key(udraw->joy_input_dev, BTN_MODE, !!(data[1] & 16));

	x = y = 0;
	switch (data[2]) {
	case 0x0:
		y = -127;
		break;
	case 0x1:
		y = -127;
		x = 127;
		break;
	case 0x2:
		x = 127;
		break;
	case 0x3:
		y = 127;
		x = 127;
		break;
	case 0x4:
		y = 127;
		break;
	case 0x5:
		y = 127;
		x = -127;
		break;
	case 0x6:
		x = -127;
		break;
	case 0x7:
		y = -127;
		x = -127;
		break;
	default:
		break;
	}

	input_report_abs(udraw->joy_input_dev, ABS_X, x);
	input_report_abs(udraw->joy_input_dev, ABS_Y, y);

	input_sync(udraw->joy_input_dev);

	/* For pen and touchpad */
	x = y = 0;
	if (touch != TOUCH_NONE) {
		if (data[15] != 0x0F)
			x = data[15] * 256 + data[17];
		if (data[16] != 0x0F)
			y = data[16] * 256 + data[18];
	}

	if (touch == TOUCH_FINGER) {
		/* Save the last one-finger touch */
		udraw->last_one_finger_x = x;
		udraw->last_one_finger_y = y;
		udraw->last_two_finger_x = -1;
		udraw->last_two_finger_y = -1;
	} else if (touch == TOUCH_TWOFINGER) {
		/*
		 * We have a problem because x/y is the one for the
		 * second finger but we want the first finger given
		 * to user-space otherwise it'll look as if it jumped.
		 *
		 * See the udraw struct definition for why this was
		 * implemented this way.
		 */
		if (udraw->last_two_finger_x == -1) {
			/* Save the position of the 2nd finger */
			udraw->last_two_finger_x = x;
			udraw->last_two_finger_y = y;

			x = udraw->last_one_finger_x;
			y = udraw->last_one_finger_y;
		} else {
			/*
			 * Offset the 2-finger coords using the
			 * saved data from the first finger
			 */
			x = x - (udraw->last_two_finger_x
				- udraw->last_one_finger_x);
			y = y - (udraw->last_two_finger_y
				- udraw->last_one_finger_y);
		}
	}

	/* touchpad */
	if (touch == TOUCH_FINGER || touch == TOUCH_TWOFINGER) {
		input_report_key(udraw->touch_input_dev, BTN_TOUCH, 1);
		input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER,
				touch == TOUCH_FINGER);
		input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP,
				touch == TOUCH_TWOFINGER);

		input_report_abs(udraw->touch_input_dev, ABS_X, x);
		input_report_abs(udraw->touch_input_dev, ABS_Y, y);
	} else {
		input_report_key(udraw->touch_input_dev, BTN_TOUCH, 0);
		input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER, 0);
		input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP, 0);
	}
	input_sync(udraw->touch_input_dev);

	/* pen */
	if (touch == TOUCH_PEN) {
		int level;

		level = clamp(data[13] - PRESSURE_OFFSET,
				0, MAX_PRESSURE);

		input_report_key(udraw->pen_input_dev, BTN_TOUCH, (level != 0));
		input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 1);
		input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, level);
		input_report_abs(udraw->pen_input_dev, ABS_X, x);
		input_report_abs(udraw->pen_input_dev, ABS_Y, y);
	} else {
		input_report_key(udraw->pen_input_dev, BTN_TOUCH, 0);
		input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 0);
		input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, 0);
	}
	input_sync(udraw->pen_input_dev);

	/* accel */
	x = (data[19] + (data[20] << 8));
	x = clamp_accel(x, AXIS_X);
	y = (data[21] + (data[22] << 8));
	y = clamp_accel(y, AXIS_Y);
	z = (data[23] + (data[24] << 8));
	z = clamp_accel(z, AXIS_Z);
	input_report_abs(udraw->accel_input_dev, ABS_X, x);
	input_report_abs(udraw->accel_input_dev, ABS_Y, y);
	input_report_abs(udraw->accel_input_dev, ABS_Z, z);
	input_sync(udraw->accel_input_dev);

	/* let hidraw and hiddev handle the report */
	return 0;
}