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"); } }
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"); } } } }
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); } } }
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); }
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); } } }
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"); } } } }
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); } } }
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; } }
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; } }
/** * 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); }