static int ntrig_event()

in hid-ntrig.c [566:856]


static int ntrig_event (struct hid_device *hid, struct hid_field *field,
			struct hid_usage *usage, __s32 value)
{
	struct ntrig_data *nd = hid_get_drvdata(hid);
	struct input_dev *input;

	/* Skip processing if not a claimed input */
	if (!(hid->claimed & HID_CLAIMED_INPUT))
		goto not_claimed_input;

	/* This function is being called before the structures are fully
	 * initialized */
	if(!(field->hidinput && field->hidinput->input))
		return -EINVAL;

	input = field->hidinput->input;

	/* No special handling needed for the pen */
	if (field->application == HID_DG_PEN)
		return 0;

	switch (usage->hid) {
	case 0xff000001:
		/* Tag indicating the start of a multitouch group */
		nd->reading_mt = true;
		nd->first_contact_touch = false;
		break;
	case HID_DG_TIPSWITCH:
		nd->tipswitch = value;
		/* Prevent emission of touch until validated */
		return 1;
	case HID_DG_CONFIDENCE:
		nd->confidence = value;
		break;
	case HID_GD_X:
		nd->x = value;
		/* Clear the contact footer */
		nd->mt_foot_count = 0;
		break;
	case HID_GD_Y:
		nd->y = value;
		break;
	case HID_DG_CONTACTID:
		nd->id = value;
		break;
	case HID_DG_WIDTH:
		nd->w = value;
		break;
	case HID_DG_HEIGHT:
		nd->h = value;
		/*
		 * when in single touch mode, this is the last
		 * report received in a finger event. We want
		 * to emit a normal (X, Y) position
		 */
		if (!nd->reading_mt) {
			/*
			 * TipSwitch indicates the presence of a
			 * finger in single touch mode.
			 */
			input_report_key(input, BTN_TOUCH,
					 nd->tipswitch);
			input_report_key(input, BTN_TOOL_DOUBLETAP,
					 nd->tipswitch);
			input_event(input, EV_ABS, ABS_X, nd->x);
			input_event(input, EV_ABS, ABS_Y, nd->y);
		}
		break;
	case 0xff000002:
		/*
		 * we receive this when the device is in multitouch
		 * mode. The first of the three values tagged with
		 * this usage tells if the contact point is real
		 * or a placeholder
		 */

		/* Shouldn't get more than 4 footer packets, so skip */
		if (nd->mt_foot_count >= 4)
			break;

		nd->mt_footer[nd->mt_foot_count++] = value;

		/* if the footer isn't complete break */
		if (nd->mt_foot_count != 4)
			break;

		/* Pen activity signal. */
		if (nd->mt_footer[2]) {
			/*
			 * When the pen deactivates touch, we see a
			 * bogus frame with ContactCount > 0.
			 * We can
			 * save a bit of work by ensuring act_state < 0
			 * even if deactivation slack is turned off.
			 */
			nd->act_state = deactivate_slack - 1;
			nd->confidence = false;
			break;
		}

		/*
		 * The first footer value indicates the presence of a
		 * finger.
		 */
		if (nd->mt_footer[0]) {
			/*
			 * We do not want to process contacts under
			 * the size threshold, but do not want to
			 * ignore them for activation state
			 */
			if (nd->w < nd->min_width ||
			    nd->h < nd->min_height)
				nd->confidence = false;
		} else
			break;

		if (nd->act_state > 0) {
			/*
			 * Contact meets the activation size threshold
			 */
			if (nd->w >= nd->activation_width &&
			    nd->h >= nd->activation_height) {
				if (nd->id)
					/*
					 * first contact, activate now
					 */
					nd->act_state = 0;
				else {
					/*
					 * avoid corrupting this frame
					 * but ensure next frame will
					 * be active
					 */
					nd->act_state = 1;
					break;
				}
			} else
				/*
				 * Defer adjusting the activation state
				 * until the end of the frame.
				 */
				break;
		}

		/* Discarding this contact */
		if (!nd->confidence)
			break;

		/* emit a normal (X, Y) for the first point only */
		if (nd->id == 0) {
			/*
			 * TipSwitch is superfluous in multitouch
			 * mode.  The footer events tell us
			 * if there is a finger on the screen or
			 * not.
			 */
			nd->first_contact_touch = nd->confidence;
			input_event(input, EV_ABS, ABS_X, nd->x);
			input_event(input, EV_ABS, ABS_Y, nd->y);
		}

		/* Emit MT events */
		input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
		input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);

		/*
		 * Translate from height and width to size
		 * and orientation.
		 */
		if (nd->w > nd->h) {
			input_event(input, EV_ABS,
					ABS_MT_ORIENTATION, 1);
			input_event(input, EV_ABS,
					ABS_MT_TOUCH_MAJOR, nd->w);
			input_event(input, EV_ABS,
					ABS_MT_TOUCH_MINOR, nd->h);
		} else {
			input_event(input, EV_ABS,
					ABS_MT_ORIENTATION, 0);
			input_event(input, EV_ABS,
					ABS_MT_TOUCH_MAJOR, nd->h);
			input_event(input, EV_ABS,
					ABS_MT_TOUCH_MINOR, nd->w);
		}
		input_mt_sync(field->hidinput->input);
		break;

	case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
		if (!nd->reading_mt) /* Just to be sure */
			break;

		nd->reading_mt = false;


		/*
		 * Activation state machine logic:
		 *
		 * Fundamental states:
		 *	state >  0: Inactive
		 *	state <= 0: Active
		 *	state <  -deactivate_slack:
		 *		 Pen termination of touch
		 *
		 * Specific values of interest
		 *	state == activate_slack
		 *		 no valid input since the last reset
		 *
		 *	state == 0
		 *		 general operational state
		 *
		 *	state == -deactivate_slack
		 *		 read sufficient empty frames to accept
		 *		 the end of input and reset
		 */

		if (nd->act_state > 0) { /* Currently inactive */
			if (value)
				/*
				 * Consider each live contact as
				 * evidence of intentional activity.
				 */
				nd->act_state = (nd->act_state > value)
						? nd->act_state - value
						: 0;
			else
				/*
				 * Empty frame before we hit the
				 * activity threshold, reset.
				 */
				nd->act_state = nd->activate_slack;

			/*
			 * Entered this block inactive and no
			 * coordinates sent this frame, so hold off
			 * on button state.
			 */
			break;
		} else { /* Currently active */
			if (value && nd->act_state >=
				     nd->deactivate_slack)
				/*
				 * Live point: clear accumulated
				 * deactivation count.
				 */
				nd->act_state = 0;
			else if (nd->act_state <= nd->deactivate_slack)
				/*
				 * We've consumed the deactivation
				 * slack, time to deactivate and reset.
				 */
				nd->act_state =
					nd->activate_slack;
			else { /* Move towards deactivation */
				nd->act_state--;
				break;
			}
		}

		if (nd->first_contact_touch && nd->act_state <= 0) {
			/*
			 * Check to see if we're ready to start
			 * emitting touch events.
			 *
			 * Note: activation slack will decrease over
			 * the course of the frame, and it will be
			 * inconsistent from the start to the end of
			 * the frame.  However if the frame starts
			 * with slack, first_contact_touch will still
			 * be 0 and we will not get to this point.
			 */
			input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
			input_report_key(input, BTN_TOUCH, 1);
		} else {
			input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
			input_report_key(input, BTN_TOUCH, 0);
		}
		break;

	default:
		/* fall-back to the generic hidinput handling */
		return 0;
	}

not_claimed_input:

	/* we have handled the hidinput part, now remains hiddev */
	if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
		hid->hiddev_hid_event(hid, field, usage, value);

	return 1;
}