diff --git a/[refs] b/[refs] index 7a867400eb15..3a4e4f6bb38e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 74c4fb058083b47571a4f76dcfce95085f2d8098 +refs/heads/master: 1fd8f047490dd0ec4e4db710fcbc1bd4798d944c diff --git a/trunk/drivers/hid/Kconfig b/trunk/drivers/hid/Kconfig index f5aa4a0bbffb..22a4a051f221 100644 --- a/trunk/drivers/hid/Kconfig +++ b/trunk/drivers/hid/Kconfig @@ -560,12 +560,6 @@ config GREENASIA_FF (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter and want to enable force feedback support for it. -config HID_HYPERV_MOUSE - tristate "Microsoft Hyper-V mouse driver" - depends on HYPERV - ---help--- - Select this option to enable the Hyper-V mouse driver. - config HID_SMARTJOYPLUS tristate "SmartJoy PLUS PS2/USB adapter support" depends on USB_HID diff --git a/trunk/drivers/hid/Makefile b/trunk/drivers/hid/Makefile index eed64f4214a2..1e0d2a638b28 100644 --- a/trunk/drivers/hid/Makefile +++ b/trunk/drivers/hid/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o -obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o obj-$(CONFIG_HID_KYE) += hid-kye.o diff --git a/trunk/drivers/hid/hid-core.c b/trunk/drivers/hid/hid-core.c index 848a56c0279c..f973d330464f 100644 --- a/trunk/drivers/hid/hid-core.c +++ b/trunk/drivers/hid/hid-core.c @@ -1409,6 +1409,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, diff --git a/trunk/drivers/hid/hid-ids.h b/trunk/drivers/hid/hid-ids.h index 06ce996b8b65..7bb52275bed4 100644 --- a/trunk/drivers/hid/hid-ids.h +++ b/trunk/drivers/hid/hid-ids.h @@ -235,6 +235,7 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5 0xa001 #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/trunk/drivers/hid/hid-multitouch.c b/trunk/drivers/hid/hid-multitouch.c index f1c909f1b239..a59d939dd165 100644 --- a/trunk/drivers/hid/hid-multitouch.c +++ b/trunk/drivers/hid/hid-multitouch.c @@ -662,6 +662,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, /* Elo TouchSystems IntelliTouch Plus panel */ { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, diff --git a/trunk/drivers/staging/hv/Kconfig b/trunk/drivers/staging/hv/Kconfig index 6c0dc3006476..072185ebe95b 100644 --- a/trunk/drivers/staging/hv/Kconfig +++ b/trunk/drivers/staging/hv/Kconfig @@ -9,3 +9,9 @@ config HYPERV_NET depends on HYPERV && NET help Select this option to enable the Hyper-V virtual network driver. + +config HYPERV_MOUSE + tristate "Microsoft Hyper-V mouse driver" + depends on HYPERV && HID + help + Select this option to enable the Hyper-V mouse driver. diff --git a/trunk/drivers/staging/hv/Makefile b/trunk/drivers/staging/hv/Makefile index fbe9a427a2af..0f55ceee919b 100644 --- a/trunk/drivers/staging/hv/Makefile +++ b/trunk/drivers/staging/hv/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o +obj-$(CONFIG_HYPERV_MOUSE) += hv_mouse.o hv_storvsc-y := storvsc_drv.o hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o diff --git a/trunk/drivers/hid/hid-hyperv.c b/trunk/drivers/staging/hv/hv_mouse.c similarity index 75% rename from trunk/drivers/hid/hid-hyperv.c rename to trunk/drivers/staging/hv/hv_mouse.c index 0c33ae9cf0f0..ccd39c70c527 100644 --- a/trunk/drivers/hid/hid-hyperv.c +++ b/trunk/drivers/staging/hv/hv_mouse.c @@ -14,8 +14,11 @@ */ #include #include +#include #include -#include +#include +#include +#include #include #include #include @@ -115,6 +118,7 @@ struct synthhid_input_report { #define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE) #define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE) +#define NBITS(x) (((x)/BITS_PER_LONG)+1) enum pipe_prot_msg_type { PIPE_MESSAGE_INVALID, @@ -144,8 +148,7 @@ struct mousevsc_prt_msg { */ struct mousevsc_dev { struct hv_device *device; - bool init_complete; - bool connected; + unsigned char init_complete; struct mousevsc_prt_msg protocol_req; struct mousevsc_prt_msg protocol_resp; /* Synchronize the request/response if needed */ @@ -156,11 +159,12 @@ struct mousevsc_dev { unsigned char *report_desc; u32 report_desc_size; struct hv_input_dev_info hid_dev_info; + int connected; struct hid_device *hid_device; }; -static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device) +static struct mousevsc_dev *alloc_input_device(struct hv_device *device) { struct mousevsc_dev *input_dev; @@ -172,12 +176,11 @@ static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device) input_dev->device = device; hv_set_drvdata(device, input_dev); init_completion(&input_dev->wait_event); - input_dev->init_complete = false; return input_dev; } -static void mousevsc_free_device(struct mousevsc_dev *device) +static void free_input_device(struct mousevsc_dev *device) { kfree(device->hid_desc); kfree(device->report_desc); @@ -185,6 +188,7 @@ static void mousevsc_free_device(struct mousevsc_dev *device) kfree(device); } + static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, struct synthhid_device_info *device_info) { @@ -192,12 +196,14 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, struct hid_descriptor *desc; struct mousevsc_prt_msg ack; - input_device->dev_info_status = -ENOMEM; + /* Assume success for now */ + input_device->dev_info_status = 0; + + memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info, + sizeof(struct hv_input_dev_info)); - input_device->hid_dev_info = device_info->hid_dev_info; desc = &device_info->hid_descriptor; - if (desc->bLength == 0) - goto cleanup; + WARN_ON(desc->bLength == 0); input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC); @@ -207,18 +213,13 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, memcpy(input_device->hid_desc, desc, desc->bLength); input_device->report_desc_size = desc->desc[0].wDescriptorLength; - if (input_device->report_desc_size == 0) { - input_device->dev_info_status = -EINVAL; + if (input_device->report_desc_size == 0) goto cleanup; - } - input_device->report_desc = kzalloc(input_device->report_desc_size, GFP_ATOMIC); - if (!input_device->report_desc) { - input_device->dev_info_status = -ENOMEM; + if (!input_device->report_desc) goto cleanup; - } memcpy(input_device->report_desc, ((unsigned char *)desc) + desc->bLength, @@ -241,14 +242,22 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, (unsigned long)&ack, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret != 0) + goto cleanup; - if (!ret) - input_device->dev_info_status = 0; - -cleanup: complete(&input_device->wait_event); return; + +cleanup: + kfree(input_device->hid_desc); + input_device->hid_desc = NULL; + + kfree(input_device->report_desc); + input_device->report_desc = NULL; + + input_device->dev_info_status = -1; + complete(&input_device->wait_event); } static void mousevsc_on_receive(struct hv_device *device, @@ -265,22 +274,10 @@ static void mousevsc_on_receive(struct hv_device *device, if (pipe_msg->type != PIPE_MESSAGE_DATA) return; - hid_msg = (struct synthhid_msg *)pipe_msg->data; + hid_msg = (struct synthhid_msg *)&pipe_msg->data[0]; 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)); @@ -295,11 +292,11 @@ static void mousevsc_on_receive(struct hv_device *device, * hid desc and report desc */ mousevsc_on_receive_device_info(input_dev, - (struct synthhid_device_info *)pipe_msg->data); + (struct synthhid_device_info *)&pipe_msg->data[0]); break; case SYNTH_HID_INPUT_REPORT: input_report = - (struct synthhid_input_report *)pipe_msg->data; + (struct synthhid_input_report *)&pipe_msg->data[0]; if (!input_dev->init_complete) break; hid_input_report(input_dev->hid_device, @@ -316,60 +313,73 @@ static void mousevsc_on_receive(struct hv_device *device, static void mousevsc_on_channel_callback(void *context) { - const int packet_size = 0x100; - int ret; - struct hv_device *device = context; + const int packetSize = 0x100; + int ret = 0; + struct hv_device *device = (struct hv_device *)context; + u32 bytes_recvd; u64 req_id; + unsigned char packet[0x100]; struct vmpacket_descriptor *desc; - unsigned char *buffer; - int bufferlen = packet_size; + unsigned char *buffer = packet; + int bufferlen = packetSize; - buffer = kmalloc(bufferlen, GFP_ATOMIC); - if (!buffer) - return; do { ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, &bytes_recvd, &req_id); - switch (ret) { - case 0: - if (bytes_recvd <= 0) { - kfree(buffer); - return; - } - desc = (struct vmpacket_descriptor *)buffer; - - switch (desc->type) { - case VM_PKT_COMP: - break; - - case VM_PKT_DATA_INBAND: - mousevsc_on_receive(device, desc); - break; - - default: - pr_err("unhandled packet type %d, tid %llx len %d\n", - desc->type, req_id, bytes_recvd); + if (ret == 0) { + if (bytes_recvd > 0) { + desc = (struct vmpacket_descriptor *)buffer; + + switch (desc->type) { + case VM_PKT_COMP: + break; + + case VM_PKT_DATA_INBAND: + mousevsc_on_receive( + device, desc); + break; + + default: + pr_err("unhandled packet type %d, tid %llx len %d\n", + desc->type, + req_id, + bytes_recvd); + break; + } + + /* reset */ + if (bufferlen > packetSize) { + kfree(buffer); + + buffer = packet; + bufferlen = packetSize; + } + } else { + if (bufferlen > packetSize) { + kfree(buffer); + + buffer = packet; + bufferlen = packetSize; + } break; } - - break; - - case -ENOBUFS: - kfree(buffer); + } else if (ret == -ENOBUFS) { /* Handle large packet */ bufferlen = bytes_recvd; - buffer = kmalloc(bytes_recvd, GFP_ATOMIC); - - if (!buffer) - return; + buffer = kzalloc(bytes_recvd, GFP_ATOMIC); - break; + if (buffer == NULL) { + buffer = packet; + bufferlen = packetSize; + break; + } } } while (1); + return; } static int mousevsc_connect_to_vsp(struct hv_device *device) @@ -380,15 +390,19 @@ static int mousevsc_connect_to_vsp(struct hv_device *device) struct mousevsc_prt_msg *request; struct mousevsc_prt_msg *response; + request = &input_dev->protocol_req; + memset(request, 0, sizeof(struct mousevsc_prt_msg)); request->type = PIPE_MESSAGE_DATA; request->size = sizeof(struct synthhid_protocol_request); + request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST; request->request.header.size = sizeof(unsigned int); request->request.version_requested.version = SYNTHHID_INPUT_VERSION; + ret = vmbus_sendpacket(device->channel, request, sizeof(struct pipe_prt_msg) - sizeof(unsigned char) + @@ -396,11 +410,11 @@ static int mousevsc_connect_to_vsp(struct hv_device *device) (unsigned long)request, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret) + if (ret != 0) goto cleanup; t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (!t) { + if (t == 0) { ret = -ETIMEDOUT; goto cleanup; } @@ -408,14 +422,14 @@ static int mousevsc_connect_to_vsp(struct hv_device *device) response = &input_dev->protocol_resp; if (!response->response.approved) { - pr_err("synthhid protocol request failed (version %d)\n", + pr_err("synthhid protocol request failed (version %d)", SYNTHHID_INPUT_VERSION); ret = -ENODEV; goto cleanup; } t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); - if (!t) { + if (t == 0) { ret = -ETIMEDOUT; goto cleanup; } @@ -424,9 +438,11 @@ static int mousevsc_connect_to_vsp(struct hv_device *device) * We should have gotten the device attr, hid desc and report * desc at this point */ - ret = input_dev->dev_info_status; + if (input_dev->dev_info_status) + ret = -ENOMEM; cleanup: + return ret; } @@ -435,40 +451,61 @@ static int mousevsc_hid_open(struct hid_device *hid) return 0; } -static int mousevsc_hid_start(struct hid_device *hid) -{ - return 0; -} - static void mousevsc_hid_close(struct hid_device *hid) { } -static void mousevsc_hid_stop(struct hid_device *hid) -{ -} - static struct hid_ll_driver mousevsc_ll_driver = { .open = mousevsc_hid_open, .close = mousevsc_hid_close, - .start = mousevsc_hid_start, - .stop = mousevsc_hid_stop, }; static struct hid_driver mousevsc_hid_driver; -static int mousevsc_probe(struct hv_device *device, - const struct hv_vmbus_device_id *dev_id) +static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len) { - int ret; - struct mousevsc_dev *input_dev; struct hid_device *hid_dev; + struct mousevsc_dev *input_device = hv_get_drvdata(dev); - input_dev = mousevsc_alloc_device(device); + hid_dev = hid_allocate_device(); + if (IS_ERR(hid_dev)) + return; + + hid_dev->ll_driver = &mousevsc_ll_driver; + hid_dev->driver = &mousevsc_hid_driver; + + if (hid_parse_report(hid_dev, packet, len)) + return; + + hid_dev->bus = BUS_VIRTUAL; + hid_dev->vendor = input_device->hid_dev_info.vendor; + hid_dev->product = input_device->hid_dev_info.product; + hid_dev->version = input_device->hid_dev_info.version; + + sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); + + if (!hidinput_connect(hid_dev, 0)) { + hid_dev->claimed |= HID_CLAIMED_INPUT; + + input_device->connected = 1; + + } + + input_device->hid_device = hid_dev; +} + +static int mousevsc_on_device_add(struct hv_device *device) +{ + int ret = 0; + struct mousevsc_dev *input_dev; + + input_dev = alloc_input_device(device); if (!input_dev) return -ENOMEM; + input_dev->init_complete = false; + ret = vmbus_open(device->channel, INPUTVSC_SEND_RING_BUFFER_SIZE, INPUTVSC_RECV_RING_BUFFER_SIZE, @@ -478,78 +515,54 @@ static int mousevsc_probe(struct hv_device *device, device ); - if (ret) - goto probe_err0; + if (ret != 0) { + free_input_device(input_dev); + return ret; + } + ret = mousevsc_connect_to_vsp(device); - if (ret) - goto probe_err1; + if (ret != 0) { + vmbus_close(device->channel); + free_input_device(input_dev); + return ret; + } + /* workaround SA-167 */ if (input_dev->report_desc[14] == 0x25) input_dev->report_desc[14] = 0x29; - hid_dev = hid_allocate_device(); - if (IS_ERR(hid_dev)) { - ret = PTR_ERR(hid_dev); - goto probe_err1; - } - - hid_dev->ll_driver = &mousevsc_ll_driver; - hid_dev->driver = &mousevsc_hid_driver; - hid_dev->bus = BUS_VIRTUAL; - hid_dev->vendor = input_dev->hid_dev_info.vendor; - hid_dev->product = input_dev->hid_dev_info.product; - hid_dev->version = input_dev->hid_dev_info.version; - input_dev->hid_device = hid_dev; - - sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); - - ret = hid_add_device(hid_dev); - if (ret) - goto probe_err1; - - ret = hid_parse_report(hid_dev, input_dev->report_desc, - input_dev->report_desc_size); - - if (ret) { - hid_err(hid_dev, "parse failed\n"); - goto probe_err2; - } + reportdesc_callback(device, input_dev->report_desc, + input_dev->report_desc_size); - ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); - - if (ret) { - hid_err(hid_dev, "hw start failed\n"); - goto probe_err2; - } - - input_dev->connected = true; input_dev->init_complete = true; return ret; +} -probe_err2: - hid_destroy_device(hid_dev); - -probe_err1: - vmbus_close(device->channel); +static int mousevsc_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) +{ -probe_err0: - mousevsc_free_device(input_dev); + return mousevsc_on_device_add(dev); - return ret; } - static int mousevsc_remove(struct hv_device *dev) { struct mousevsc_dev *input_dev = hv_get_drvdata(dev); vmbus_close(dev->channel); - hid_destroy_device(input_dev->hid_device); - mousevsc_free_device(input_dev); + + if (input_dev->connected) { + hidinput_disconnect(input_dev->hid_device); + input_dev->connected = 0; + hid_destroy_device(input_dev->hid_device); + } + + free_input_device(input_dev); return 0; } @@ -564,7 +577,7 @@ static const struct hv_vmbus_device_id id_table[] = { MODULE_DEVICE_TABLE(vmbus, id_table); static struct hv_driver mousevsc_drv = { - .name = KBUILD_MODNAME, + .name = "mousevsc", .id_table = id_table, .probe = mousevsc_probe, .remove = mousevsc_remove,