static void joycon_parse_report()

in hid-nintendo.c [1214:1377]


static void joycon_parse_report(struct joycon_ctlr *ctlr,
				struct joycon_input_report *rep)
{
	struct input_dev *dev = ctlr->input;
	unsigned long flags;
	u8 tmp;
	u32 btns;
	unsigned long msecs = jiffies_to_msecs(jiffies);

	spin_lock_irqsave(&ctlr->lock, flags);
	if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
	    (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS &&
	    (ctlr->rumble_queue_head != ctlr->rumble_queue_tail ||
	     ctlr->rumble_zero_countdown > 0)) {
		/*
		 * When this value reaches 0, we know we've sent multiple
		 * packets to the controller instructing it to disable rumble.
		 * We can safely stop sending periodic rumble packets until the
		 * next ff effect.
		 */
		if (ctlr->rumble_zero_countdown > 0)
			ctlr->rumble_zero_countdown--;
		queue_work(ctlr->rumble_queue, &ctlr->rumble_worker);
	}

	/* Parse the battery status */
	tmp = rep->bat_con;
	ctlr->host_powered = tmp & BIT(0);
	ctlr->battery_charging = tmp & BIT(4);
	tmp = tmp >> 5;
	switch (tmp) {
	case 0: /* empty */
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
		break;
	case 1: /* low */
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
		break;
	case 2: /* medium */
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
		break;
	case 3: /* high */
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
		break;
	case 4: /* full */
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
		break;
	default:
		ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
		hid_warn(ctlr->hdev, "Invalid battery status\n");
		break;
	}
	spin_unlock_irqrestore(&ctlr->lock, flags);

	/* Parse the buttons and sticks */
	btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24);

	if (jc_type_has_left(ctlr)) {
		u16 raw_x;
		u16 raw_y;
		s32 x;
		s32 y;

		/* get raw stick values */
		raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12);
		raw_y = hid_field_extract(ctlr->hdev,
					  rep->left_stick + 1, 4, 12);
		/* map the stick values */
		x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x);
		y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y);
		/* report sticks */
		input_report_abs(dev, ABS_X, x);
		input_report_abs(dev, ABS_Y, y);

		/* report buttons */
		input_report_key(dev, BTN_TL, btns & JC_BTN_L);
		input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
		input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
		input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK);
		input_report_key(dev, BTN_Z, btns & JC_BTN_CAP);

		if (jc_type_is_joycon(ctlr)) {
			/* Report the S buttons as the non-existent triggers */
			input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L);
			input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L);

			/* Report d-pad as digital buttons for the joy-cons */
			input_report_key(dev, BTN_DPAD_DOWN,
					 btns & JC_BTN_DOWN);
			input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP);
			input_report_key(dev, BTN_DPAD_RIGHT,
					 btns & JC_BTN_RIGHT);
			input_report_key(dev, BTN_DPAD_LEFT,
					 btns & JC_BTN_LEFT);
		} else {
			int hatx = 0;
			int haty = 0;

			/* d-pad x */
			if (btns & JC_BTN_LEFT)
				hatx = -1;
			else if (btns & JC_BTN_RIGHT)
				hatx = 1;
			input_report_abs(dev, ABS_HAT0X, hatx);

			/* d-pad y */
			if (btns & JC_BTN_UP)
				haty = -1;
			else if (btns & JC_BTN_DOWN)
				haty = 1;
			input_report_abs(dev, ABS_HAT0Y, haty);
		}
	}
	if (jc_type_has_right(ctlr)) {
		u16 raw_x;
		u16 raw_y;
		s32 x;
		s32 y;

		/* get raw stick values */
		raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12);
		raw_y = hid_field_extract(ctlr->hdev,
					  rep->right_stick + 1, 4, 12);
		/* map stick values */
		x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x);
		y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y);
		/* report sticks */
		input_report_abs(dev, ABS_RX, x);
		input_report_abs(dev, ABS_RY, y);

		/* report buttons */
		input_report_key(dev, BTN_TR, btns & JC_BTN_R);
		input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR);
		if (jc_type_is_joycon(ctlr)) {
			/* Report the S buttons as the non-existent triggers */
			input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R);
			input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R);
		}
		input_report_key(dev, BTN_START, btns & JC_BTN_PLUS);
		input_report_key(dev, BTN_THUMBR, btns & JC_BTN_RSTICK);
		input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME);
		input_report_key(dev, BTN_WEST, btns & JC_BTN_Y);
		input_report_key(dev, BTN_NORTH, btns & JC_BTN_X);
		input_report_key(dev, BTN_EAST, btns & JC_BTN_A);
		input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B);
	}

	input_sync(dev);

	/*
	 * Immediately after receiving a report is the most reliable time to
	 * send a subcommand to the controller. Wake any subcommand senders
	 * waiting for a report.
	 */
	if (unlikely(mutex_is_locked(&ctlr->output_mutex))) {
		spin_lock_irqsave(&ctlr->lock, flags);
		ctlr->received_input_report = true;
		spin_unlock_irqrestore(&ctlr->lock, flags);
		wake_up(&ctlr->wait);
	}

	/* parse IMU data if present */
	if (rep->id == JC_INPUT_IMU_DATA)
		joycon_parse_imu_report(ctlr, rep);
}