Esempio n. 1
0
static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
					struct dj_report *dj_report)
{
	/* We are called from atomic context (tasklet && djrcv->lock held) */
	struct dj_device *dj_device;

	dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];

	if (dj_device == NULL) {
		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
			" is NULL, index %d\n", dj_report->device_index);
		return;
	}

	if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
	    (hid_reportid_size_map[dj_report->report_type] == 0)) {
		dbg_hid("invalid report type:%x\n", dj_report->report_type);
		return;
	}

	if (hid_input_report(dj_device->hdev,
			HID_INPUT_REPORT, &dj_report->report_type,
			hid_reportid_size_map[dj_report->report_type], 1)) {
		dbg_hid("hid_input_report error\n");
	}
}
static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
					struct dj_report *dj_report)
{
	
	struct dj_device *dj_device;

	dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];

	if (dj_device == NULL) {
		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
			" is NULL, index %d\n", dj_report->device_index);
		kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));

		if (schedule_work(&djrcv_dev->work) == 0) {
			dbg_hid("%s: did not schedule the work item, was already "
			"queued\n", __func__);
		}
		return;
	}

	if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
	    (hid_reportid_size_map[dj_report->report_type] == 0)) {
		dbg_hid("invalid report type:%x\n", dj_report->report_type);
		return;
	}

	if (hid_input_report(dj_device->hdev,
			HID_INPUT_REPORT, &dj_report->report_type,
			hid_reportid_size_map[dj_report->report_type], 1)) {
		dbg_hid("hid_input_report error\n");
	}
}
Esempio n. 3
0
static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
					     struct dj_report *dj_report)
{
	/* We are called from atomic context (tasklet && djrcv->lock held) */
	unsigned int i;
	u8 reportbuffer[MAX_REPORT_SIZE];
	struct dj_device *djdev;

	djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];

	if (!djdev) {
		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
			" is NULL, index %d\n", dj_report->device_index);
		return;
	}

	memset(reportbuffer, 0, sizeof(reportbuffer));

	for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
		if (djdev->reports_supported & (1 << i)) {
			reportbuffer[0] = i;
			if (hid_input_report(djdev->hdev,
					     HID_INPUT_REPORT,
					     reportbuffer,
					     hid_reportid_size_map[i], 1)) {
				dbg_hid("hid_input_report error sending null "
					"report\n");
			}
		}
	}
}
Esempio n. 4
0
static void hid_irq_in(struct urb *urb)
{
	struct hid_device	*hid = urb->context;
	struct usbhid_device 	*usbhid = hid->driver_data;
	int			status;

	switch (urb->status) {
	case 0:			/* success */
		usbhid_mark_busy(usbhid);
		usbhid->retry_delay = 0;
		hid_input_report(urb->context, HID_INPUT_REPORT,
				 urb->transfer_buffer,
				 urb->actual_length, 1);
		/*
		 * autosuspend refused while keys are pressed
		 * because most keyboards don't wake up when
		 * a key is released
		 */
		if (hid_check_keys_pressed(hid))
			set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
		else
			clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
		break;
	case -EOVERFLOW:
	case -EPIPE:		/* stall */
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		set_bit((urb->status == -EPIPE)? HID_CLEAR_HALT:HID_RESET_PENDING, &usbhid->iofl);
		schedule_work(&usbhid->reset_work);
		return;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:	/* unplug */
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		return;
	case -EILSEQ:		/* protocol error or unplug */
	case -EPROTO:		/* protocol error or unplug */
	case -ETIME:		/* protocol error or unplug */
	case -ETIMEDOUT:	/* Should never happen, but... */
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		hid_io_error(hid);
		return;
	default:		/* error */
		dev_warn(&urb->dev->dev, "input irq status %d  "
				"received\n", urb->status);
	}

	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		if (status != -EPERM) {
			err_hid("can't resubmit intr, %s-%s/input%d, status %d",
					hid_to_usb_dev(hid)->bus->bus_name,
					hid_to_usb_dev(hid)->devpath,
					usbhid->ifnum, status);
			hid_io_error(hid);
		}
	}
}
Esempio n. 5
0
static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
{
	if (!uhid->running)
		return -EINVAL;

	return hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
}
Esempio n. 6
0
static void hid_irq_in(struct urb *urb)
{
	struct hid_device	*hid = urb->context;
	struct usbhid_device 	*usbhid = hid->driver_data;
	int			status;

	switch (urb->status) {
	case 0:			
		usbhid_mark_busy(usbhid);
		usbhid->retry_delay = 0;
		hid_input_report(urb->context, HID_INPUT_REPORT,
				 urb->transfer_buffer,
				 urb->actual_length, 1);
		
		if (hid_check_keys_pressed(hid))
			set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
		else
			clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
		break;
	case -EPIPE:		
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		set_bit(HID_CLEAR_HALT, &usbhid->iofl);
		schedule_work(&usbhid->reset_work);
		return;
	case -ECONNRESET:	
	case -ENOENT:
	case -ESHUTDOWN:	
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		return;
	case -EILSEQ:		
	case -EPROTO:		
	case -ETIME:		
	case -ETIMEDOUT:	
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		hid_io_error(hid);
		return;
	default:		
		dev_warn(&urb->dev->dev, "input irq status %d  "
				"received\n", urb->status);
	}

	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		if (status != -EPERM) {
			err_hid("can't resubmit intr, %s-%s/input%d, status %d",
					hid_to_usb_dev(hid)->bus->bus_name,
					hid_to_usb_dev(hid)->devpath,
					usbhid->ifnum, status);
			hid_io_error(hid);
		}
	}
}
Esempio n. 7
0
static ssize_t bthid_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    unsigned char *buf;
    struct bthid_device *p_dev = file->private_data;

    /*
#ifdef CONFIG_DEBUG_PRINTK
    printk("######## bthid_write: count = %d ########\n", count);
#else
    ;
#endif
    */

    if (p_dev->dscp_set == 0) {
#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO "bthid_write: Oops, HID report descriptor not configured\n");
#else
	;
#endif
        return 0;
    }

    buf = kmalloc(count + 1, GFP_KERNEL);
    if (!buf)
    {
        return -ENOMEM;
    }

    if (copy_from_user(buf, buffer, count))
    {
        kfree(buf);
        return -EFAULT;
    }

    if (p_dev->hid) 
    {
        hid_input_report(p_dev->hid, HID_INPUT_REPORT, buf, count, 1);
    }

    kfree(buf);

    /*
#ifdef CONFIG_DEBUG_PRINTK
    printk("######## bthid_write: done ########\n");
#else
    ;
#endif
    */

    return 0;
}
static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
					     struct dj_report *dj_report)
{
	
	unsigned int i;
	u8 reportbuffer[MAX_REPORT_SIZE];
	struct dj_device *djdev;

	djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];

	if (!djdev) {
		dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
			" is NULL, index %d\n", dj_report->device_index);
		kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));

		if (schedule_work(&djrcv_dev->work) == 0) {
			dbg_hid("%s: did not schedule the work item, was already "
			"queued\n", __func__);
		}
		return;
	}

	memset(reportbuffer, 0, sizeof(reportbuffer));

	for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
		if (djdev->reports_supported & (1 << i)) {
			reportbuffer[0] = i;
			if (hid_input_report(djdev->hdev,
					     HID_INPUT_REPORT,
					     reportbuffer,
					     hid_reportid_size_map[i], 1)) {
				dbg_hid("hid_input_report error sending null "
					"report\n");
			}
		}
	}
}
Esempio n. 9
0
static void hid_irq_in(struct urb *urb)
{
	struct hid_device	*hid = urb->context;
	struct usbhid_device 	*usbhid = hid->driver_data;
	int			status;

	switch (urb->status) {
	case 0:			/* success */
		usbhid_mark_busy(usbhid);
		usbhid->retry_delay = 0;
#if defined(CONFIG_TOUCHSCREEN_NEXIO_USB)
		if((hid->vendor == NEXIO_USB_TOUCH_VENDOR) && (hid->product == NEXIO_USB_TOUCH_PRODUCT))	{
			if(nexio_touch_driver_open)	{
				nexio_touch_report_data(urb->transfer_buffer, urb->actual_length);
			}
		}
		else	
#endif
#if defined(CONFIG_TOUCHSCREEN_EGALAX_USB)
		if((hid->vendor == EGALAX_USB_TOUCH_VENDOR) && (hid->product == EGALAX_USB_TOUCH_PRODUCT))	{
			if(egalax_touch_driver_open)	{
				egalax_touch_report_data(urb->transfer_buffer, urb->actual_length);
			}
		}
		else	
#endif
		{
			hid_input_report(urb->context, HID_INPUT_REPORT,
					 urb->transfer_buffer,
					 urb->actual_length, 1);
			/*
			 * autosuspend refused while keys are pressed
			 * because most keyboards don't wake up when
			 * a key is released
			 */
			if (hid_check_keys_pressed(hid))
				set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
			else
				clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
		}
		break;
	case -EPIPE:		/* stall */
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		set_bit(HID_CLEAR_HALT, &usbhid->iofl);
		schedule_work(&usbhid->reset_work);
		return;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:	/* unplug */
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		return;
	case -EILSEQ:		/* protocol error or unplug */
	case -EPROTO:		/* protocol error or unplug */
	case -ETIME:		/* protocol error or unplug */
	case -ETIMEDOUT:	/* Should never happen, but... */
		usbhid_mark_busy(usbhid);
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		hid_io_error(hid);
		return;
	default:		/* error */
		hid_warn(urb->dev, "input irq status %d received\n",
			 urb->status);
	}

	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
		if (status != -EPERM) {
			hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
				hid_to_usb_dev(hid)->bus->bus_name,
				hid_to_usb_dev(hid)->devpath,
				usbhid->ifnum, status);
			hid_io_error(hid);
		}
	}
}
Esempio n. 10
0
static void mousevsc_on_receive(struct hv_device *device,
				struct vmpacket_descriptor *packet)
{
	struct pipe_prt_msg *pipe_msg;
	struct synthhid_msg *hid_msg;
	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
	struct synthhid_input_report *input_report;

	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
						(packet->offset8 << 3));

	if (pipe_msg->type != PIPE_MESSAGE_DATA)
		return;

	hid_msg = (struct synthhid_msg *)pipe_msg->data;

	switch (hid_msg->header.type) {
	case SYNTH_HID_PROTOCOL_RESPONSE:
		/*
		 * While it will be impossible for us to protect against
		 * malicious/buggy hypervisor/host, add a check here to
		 * ensure we don't corrupt memory.
		 */
		if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
			- sizeof(unsigned char))
			> sizeof(struct mousevsc_prt_msg)) {
			WARN_ON(1);
			break;
		}

		memcpy(&input_dev->protocol_resp, pipe_msg,
		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
		       sizeof(unsigned char));
		complete(&input_dev->wait_event);
		break;

	case SYNTH_HID_INITIAL_DEVICE_INFO:
		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));

		/*
		 * Parse out the device info into device attr,
		 * hid desc and report desc
		 */
		mousevsc_on_receive_device_info(input_dev,
			(struct synthhid_device_info *)pipe_msg->data);
		break;
	case SYNTH_HID_INPUT_REPORT:
		input_report =
			(struct synthhid_input_report *)pipe_msg->data;
		if (!input_dev->init_complete)
			break;
		hid_input_report(input_dev->hid_device,
				HID_INPUT_REPORT, input_report->buffer,
				input_report->header.size, 1);
		break;
	default:
		pr_err("unsupported hid msg type - type %d len %d",
		       hid_msg->header.type, hid_msg->header.size);
		break;
	}

}
Esempio n. 11
0
static void mousevsc_on_receive(struct hv_device *device,
				struct vmpacket_descriptor *packet)
{
	struct pipe_prt_msg *pipe_msg;
	struct synthhid_msg *hid_msg;
	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
	struct synthhid_input_report *input_report;

	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
						(packet->offset8 << 3));

	if (pipe_msg->type != PIPE_MESSAGE_DATA)
		return;

	hid_msg = (struct synthhid_msg *)pipe_msg->data;

	switch (hid_msg->header.type) {
	case SYNTH_HID_PROTOCOL_RESPONSE:
		/*
                                                          
                                                         
                                    
   */
		if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
			- sizeof(unsigned char))
			> sizeof(struct mousevsc_prt_msg)) {
			WARN_ON(1);
			break;
		}

		memcpy(&input_dev->protocol_resp, pipe_msg,
		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
		       sizeof(unsigned char));
		complete(&input_dev->wait_event);
		break;

	case SYNTH_HID_INITIAL_DEVICE_INFO:
		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));

		/*
                                                
                             
   */
		mousevsc_on_receive_device_info(input_dev,
			(struct synthhid_device_info *)pipe_msg->data);
		break;
	case SYNTH_HID_INPUT_REPORT:
		input_report =
			(struct synthhid_input_report *)pipe_msg->data;
		if (!input_dev->init_complete)
			break;
		hid_input_report(input_dev->hid_device,
				HID_INPUT_REPORT, input_report->buffer,
				input_report->header.size, 1);
		break;
	default:
		pr_err("unsupported hid msg type - type %d len %d",
		       hid_msg->header.type, hid_msg->header.size);
		break;
	}

}
Esempio n. 12
0
/**
 * process_recv() - Received and parse incoming packet
 * @hid_ishtp_cl:	Client instance to get stats
 * @recv_buf:		Raw received host interface message
 * @data_len:		length of the message
 *
 * Parse the incoming packet. If it is a response packet then it will update
 * per instance flags and wake up the caller waiting to for the response.
 */
static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
			 size_t data_len)
{
	struct hostif_msg *recv_msg;
	unsigned char *payload;
	struct device_info *dev_info;
	int i, j;
	size_t	payload_len, total_len, cur_pos;
	int report_type;
	struct report_list *reports_list;
	char *reports;
	size_t report_len;
	struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
	int curr_hid_dev = client_data->cur_hid_dev;

	if (data_len < sizeof(struct hostif_msg_hdr)) {
		dev_err(&client_data->cl_device->dev,
			"[hid-ish]: error, received %u which is less than data header %u\n",
			(unsigned int)data_len,
			(unsigned int)sizeof(struct hostif_msg_hdr));
		++client_data->bad_recv_cnt;
		ish_hw_reset(hid_ishtp_cl->dev);
		return;
	}

	payload = recv_buf + sizeof(struct hostif_msg_hdr);
	total_len = data_len;
	cur_pos = 0;

	do {
		recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
		payload_len = recv_msg->hdr.size;

		/* Sanity checks */
		if (cur_pos + payload_len + sizeof(struct hostif_msg) >
				total_len) {
			++client_data->bad_recv_cnt;
			report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
					  payload_len);
			ish_hw_reset(hid_ishtp_cl->dev);
			break;
		}

		hid_ishtp_trace(client_data,  "%s %d\n",
				__func__, recv_msg->hdr.command & CMD_MASK);

		switch (recv_msg->hdr.command & CMD_MASK) {
		case HOSTIF_DM_ENUM_DEVICES:
			if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
					client_data->init_done)) {
				++client_data->bad_recv_cnt;
				report_bad_packet(hid_ishtp_cl, recv_msg,
						  cur_pos,
						  payload_len);
				ish_hw_reset(hid_ishtp_cl->dev);
				break;
			}
			client_data->hid_dev_count = (unsigned int)*payload;
			if (!client_data->hid_devices)
				client_data->hid_devices = devm_kzalloc(
						&client_data->cl_device->dev,
						client_data->hid_dev_count *
						sizeof(struct device_info),
						GFP_KERNEL);
			if (!client_data->hid_devices) {
				dev_err(&client_data->cl_device->dev,
				"Mem alloc failed for hid device info\n");
				wake_up_interruptible(&client_data->init_wait);
				break;
			}
			for (i = 0; i < client_data->hid_dev_count; ++i) {
				if (1 + sizeof(struct device_info) * i >=
						payload_len) {
					dev_err(&client_data->cl_device->dev,
						"[hid-ish]: [ENUM_DEVICES]: content size %lu is bigger than payload_len %u\n",
						1 + sizeof(struct device_info)
						* i,
						(unsigned int)payload_len);
				}

				if (1 + sizeof(struct device_info) * i >=
						data_len)
					break;

				dev_info = (struct device_info *)(payload + 1 +
					sizeof(struct device_info) * i);
				if (client_data->hid_devices)
					memcpy(client_data->hid_devices + i,
					       dev_info,
					       sizeof(struct device_info));
			}

			client_data->enum_devices_done = true;
			wake_up_interruptible(&client_data->init_wait);

			break;

		case HOSTIF_GET_HID_DESCRIPTOR:
			if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
					client_data->init_done)) {
				++client_data->bad_recv_cnt;
				report_bad_packet(hid_ishtp_cl, recv_msg,
						  cur_pos,
						  payload_len);
				ish_hw_reset(hid_ishtp_cl->dev);
				break;
			}
			if (!client_data->hid_descr[curr_hid_dev])
				client_data->hid_descr[curr_hid_dev] =
				devm_kmalloc(&client_data->cl_device->dev,
					     payload_len, GFP_KERNEL);
			if (client_data->hid_descr[curr_hid_dev]) {
				memcpy(client_data->hid_descr[curr_hid_dev],
				       payload, payload_len);
				client_data->hid_descr_size[curr_hid_dev] =
					payload_len;
				client_data->hid_descr_done = true;
			}
			wake_up_interruptible(&client_data->init_wait);

			break;

		case HOSTIF_GET_REPORT_DESCRIPTOR:
			if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
					client_data->init_done)) {
				++client_data->bad_recv_cnt;
				report_bad_packet(hid_ishtp_cl, recv_msg,
						  cur_pos,
						  payload_len);
				ish_hw_reset(hid_ishtp_cl->dev);
				break;
			}
			if (!client_data->report_descr[curr_hid_dev])
				client_data->report_descr[curr_hid_dev] =
				devm_kmalloc(&client_data->cl_device->dev,
					     payload_len, GFP_KERNEL);
			if (client_data->report_descr[curr_hid_dev])  {
				memcpy(client_data->report_descr[curr_hid_dev],
				       payload,
				       payload_len);
				client_data->report_descr_size[curr_hid_dev] =
					payload_len;
				client_data->report_descr_done = true;
			}
			wake_up_interruptible(&client_data->init_wait);

			break;

		case HOSTIF_GET_FEATURE_REPORT:
			report_type = HID_FEATURE_REPORT;
			goto	do_get_report;

		case HOSTIF_GET_INPUT_REPORT:
			report_type = HID_INPUT_REPORT;
do_get_report:
			/* Get index of device that matches this id */
			for (i = 0; i < client_data->num_hid_devices; ++i) {
				if (recv_msg->hdr.device_id ==
					client_data->hid_devices[i].dev_id)
					if (client_data->hid_sensor_hubs[i]) {
						hid_input_report(
						client_data->hid_sensor_hubs[
									i],
						report_type, payload,
						payload_len, 0);
						ishtp_hid_wakeup(
						client_data->hid_sensor_hubs[
							i]);
						break;
					}
			}
			break;

		case HOSTIF_SET_FEATURE_REPORT:
			/* Get index of device that matches this id */
			for (i = 0; i < client_data->num_hid_devices; ++i) {
				if (recv_msg->hdr.device_id ==
					client_data->hid_devices[i].dev_id)
					if (client_data->hid_sensor_hubs[i]) {
						ishtp_hid_wakeup(
						client_data->hid_sensor_hubs[
							i]);
						break;
					}
			}
			break;

		case HOSTIF_PUBLISH_INPUT_REPORT:
			report_type = HID_INPUT_REPORT;
			for (i = 0; i < client_data->num_hid_devices; ++i)
				if (recv_msg->hdr.device_id ==
					client_data->hid_devices[i].dev_id)
					if (client_data->hid_sensor_hubs[i])
						hid_input_report(
						client_data->hid_sensor_hubs[
									i],
						report_type, payload,
						payload_len, 0);
			break;

		case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
			report_type = HID_INPUT_REPORT;
			reports_list = (struct report_list *)payload;
			reports = (char *)reports_list->reports;

			for (j = 0; j < reports_list->num_of_reports; j++) {
				recv_msg = (struct hostif_msg *)(reports +
					sizeof(uint16_t));
				report_len = *(uint16_t *)reports;
				payload = reports + sizeof(uint16_t) +
					sizeof(struct hostif_msg_hdr);
				payload_len = report_len -
					sizeof(struct hostif_msg_hdr);

				for (i = 0; i < client_data->num_hid_devices;
				     ++i)
					if (recv_msg->hdr.device_id ==
					client_data->hid_devices[i].dev_id &&
					client_data->hid_sensor_hubs[i]) {
						hid_input_report(
						client_data->hid_sensor_hubs[
									i],
						report_type,
						payload, payload_len,
						0);
					}

				reports += sizeof(uint16_t) + report_len;
			}
			break;
		default:
			++client_data->bad_recv_cnt;
			report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
					  payload_len);
			ish_hw_reset(hid_ishtp_cl->dev);
			break;

		}

		if (!cur_pos && cur_pos + payload_len +
				sizeof(struct hostif_msg) < total_len)
			++client_data->multi_packet_cnt;

		cur_pos += payload_len + sizeof(struct hostif_msg);
		payload += payload_len + sizeof(struct hostif_msg);

	} while (cur_pos < total_len);
}