2 * Copyright 2009 Citrix Systems, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * For clarity, the licensor of this program does not intend that a
19 * "derivative work" include code which compiles header information from
22 * This code has been modified from its original by
23 * Hank Janssen <hjanssen@microsoft.com>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/device.h>
28 #include <linux/workqueue.h>
29 #include <linux/sched.h>
30 #include <linux/wait.h>
31 #include <linux/input.h>
32 #include <linux/hid.h>
33 #include <linux/hiddev.h>
37 #include "vmbus_api.h"
41 #include "mousevsc_api.h"
42 #include "vmbus_packet_format.h"
43 #include "vmbus_hid_protocol.h"
46 enum pipe_prot_msg_type
48 PipeMessageInvalid
= 0,
56 enum pipe_prot_msg_type PacketType
;
64 struct mousevsc_prt_msg
{
65 enum pipe_prot_msg_type PacketType
;
68 SYNTHHID_PROTOCOL_REQUEST Request
;
69 SYNTHHID_PROTOCOL_RESPONSE Response
;
70 SYNTHHID_DEVICE_INFO_ACK Ack
;
75 * Represents an mousevsc device
78 struct hv_device
*Device
;
79 /* 0 indicates the device is being destroyed */
81 int NumOutstandingRequests
;
82 unsigned char bInitializeComplete
;
83 struct mousevsc_prt_msg ProtocolReq
;
84 struct mousevsc_prt_msg ProtocolResp
;
85 /* Synchronize the request/response if needed */
86 wait_queue_head_t ProtocolWaitEvent
;
87 wait_queue_head_t DeviceInfoWaitEvent
;
88 int protocol_wait_condition
;
89 int device_wait_condition
;
92 struct hid_descriptor
*HidDesc
;
93 unsigned char *ReportDesc
;
95 struct input_dev_info DeviceAttr
;
102 static const char* gDriverName
= "mousevsc";
104 /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
105 static const struct hv_guid gMousevscDeviceType
= {
106 .data
= {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
107 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}
113 static int MousevscOnDeviceAdd(struct hv_device
*Device
, void *AdditionalInfo
);
115 static int MousevscOnDeviceRemove(struct hv_device
*Device
);
117 static void MousevscOnCleanup(struct hv_driver
*Device
);
119 static void MousevscOnChannelCallback(void *Context
);
121 static int MousevscConnectToVsp(struct hv_device
*Device
);
123 static void MousevscOnReceive(struct hv_device
*Device
,
124 struct vmpacket_descriptor
*Packet
);
126 static inline struct mousevsc_dev
*AllocInputDevice(struct hv_device
*Device
)
128 struct mousevsc_dev
*inputDevice
;
130 inputDevice
= kzalloc(sizeof(struct mousevsc_dev
), GFP_KERNEL
);
136 * Set to 2 to allow both inbound and outbound traffics
137 * (ie GetInputDevice() and MustGetInputDevice()) to proceed.
139 atomic_cmpxchg(&inputDevice
->RefCount
, 0, 2);
141 inputDevice
->Device
= Device
;
142 Device
->ext
= inputDevice
;
147 static inline void FreeInputDevice(struct mousevsc_dev
*Device
)
149 WARN_ON(atomic_read(&Device
->RefCount
) == 0);
154 * Get the inputdevice object if exists and its refcount > 1
156 static inline struct mousevsc_dev
* GetInputDevice(struct hv_device
*Device
)
158 struct mousevsc_dev
*inputDevice
;
160 inputDevice
= (struct mousevsc_dev
*)Device
->ext
;
162 // printk(KERN_ERR "-------------------------> REFCOUNT = %d",
163 // inputDevice->RefCount);
165 if (inputDevice
&& atomic_read(&inputDevice
->RefCount
) > 1)
166 atomic_inc(&inputDevice
->RefCount
);
174 * Get the inputdevice object iff exists and its refcount > 0
176 static inline struct mousevsc_dev
* MustGetInputDevice(struct hv_device
*Device
)
178 struct mousevsc_dev
*inputDevice
;
180 inputDevice
= (struct mousevsc_dev
*)Device
->ext
;
182 if (inputDevice
&& atomic_read(&inputDevice
->RefCount
))
183 atomic_inc(&inputDevice
->RefCount
);
190 static inline void PutInputDevice(struct hv_device
*Device
)
192 struct mousevsc_dev
*inputDevice
;
194 inputDevice
= (struct mousevsc_dev
*)Device
->ext
;
196 atomic_dec(&inputDevice
->RefCount
);
200 * Drop ref count to 1 to effectively disable GetInputDevice()
202 static inline struct mousevsc_dev
* ReleaseInputDevice(struct hv_device
*Device
)
204 struct mousevsc_dev
*inputDevice
;
206 inputDevice
= (struct mousevsc_dev
*)Device
->ext
;
208 /* Busy wait until the ref drop to 2, then set it to 1 */
209 while (atomic_cmpxchg(&inputDevice
->RefCount
, 2, 1) != 2)
216 * Drop ref count to 0. No one can use InputDevice object.
218 static inline struct mousevsc_dev
* FinalReleaseInputDevice(struct hv_device
*Device
)
220 struct mousevsc_dev
*inputDevice
;
222 inputDevice
= (struct mousevsc_dev
*)Device
->ext
;
224 /* Busy wait until the ref drop to 1, then set it to 0 */
225 while (atomic_cmpxchg(&inputDevice
->RefCount
, 1, 0) != 1)
235 * MousevscInitialize()
241 int mouse_vsc_initialize(struct hv_driver
*Driver
)
243 struct mousevsc_drv_obj
*inputDriver
=
244 (struct mousevsc_drv_obj
*)Driver
;
247 Driver
->name
= gDriverName
;
248 memcpy(&Driver
->dev_type
, &gMousevscDeviceType
,
249 sizeof(struct hv_guid
));
251 /* Setup the dispatch table */
252 inputDriver
->Base
.dev_add
= MousevscOnDeviceAdd
;
253 inputDriver
->Base
.dev_rm
= MousevscOnDeviceRemove
;
254 inputDriver
->Base
.cleanup
= MousevscOnCleanup
;
256 inputDriver
->OnOpen
= NULL
;
257 inputDriver
->OnClose
= NULL
;
265 * MousevscOnDeviceAdd()
268 * Callback when the device belonging to this driver is added
272 MousevscOnDeviceAdd(struct hv_device
*Device
, void *AdditionalInfo
)
275 struct mousevsc_dev
*inputDevice
;
276 struct mousevsc_drv_obj
*inputDriver
;
277 struct input_dev_info deviceInfo
;
279 inputDevice
= AllocInputDevice(Device
);
286 inputDevice
->bInitializeComplete
= false;
288 /* Open the channel */
289 ret
= vmbus_open(Device
->channel
,
290 INPUTVSC_SEND_RING_BUFFER_SIZE
,
291 INPUTVSC_RECV_RING_BUFFER_SIZE
,
294 MousevscOnChannelCallback
,
299 pr_err("unable to open channel: %d", ret
);
303 pr_info("InputVsc channel open: %d", ret
);
305 ret
= MousevscConnectToVsp(Device
);
308 pr_err("unable to connect channel: %d", ret
);
310 vmbus_close(Device
->channel
);
314 inputDriver
= (struct mousevsc_drv_obj
*)inputDevice
->Device
->drv
;
316 deviceInfo
.VendorID
= inputDevice
->DeviceAttr
.VendorID
;
317 deviceInfo
.ProductID
= inputDevice
->DeviceAttr
.ProductID
;
318 deviceInfo
.VersionNumber
= inputDevice
->DeviceAttr
.VersionNumber
;
319 strcpy(deviceInfo
.Name
, "Microsoft Vmbus HID-compliant Mouse");
321 /* Send the device info back up */
322 inputDriver
->OnDeviceInfo(Device
, &deviceInfo
);
324 /* Send the report desc back up */
325 /* workaround SA-167 */
326 if (inputDevice
->ReportDesc
[14] == 0x25)
327 inputDevice
->ReportDesc
[14] = 0x29;
329 inputDriver
->OnReportDescriptor(Device
, inputDevice
->ReportDesc
, inputDevice
->ReportDescSize
);
331 inputDevice
->bInitializeComplete
= true;
338 MousevscConnectToVsp(struct hv_device
*Device
)
341 struct mousevsc_dev
*inputDevice
;
342 struct mousevsc_prt_msg
*request
;
343 struct mousevsc_prt_msg
*response
;
345 inputDevice
= GetInputDevice(Device
);
348 pr_err("unable to get input device...device being destroyed?");
352 init_waitqueue_head(&inputDevice
->ProtocolWaitEvent
);
353 init_waitqueue_head(&inputDevice
->DeviceInfoWaitEvent
);
355 request
= &inputDevice
->ProtocolReq
;
358 * Now, initiate the vsc/vsp initialization protocol on the open channel
360 memset(request
, sizeof(struct mousevsc_prt_msg
), 0);
362 request
->PacketType
= PipeMessageData
;
363 request
->DataSize
= sizeof(SYNTHHID_PROTOCOL_REQUEST
);
365 request
->u
.Request
.Header
.Type
= SynthHidProtocolRequest
;
366 request
->u
.Request
.Header
.Size
= sizeof(unsigned long);
367 request
->u
.Request
.VersionRequested
.AsDWord
=
368 SYNTHHID_INPUT_VERSION_DWORD
;
370 pr_info("SYNTHHID_PROTOCOL_REQUEST...");
372 ret
= vmbus_sendpacket(Device
->channel
, request
,
373 sizeof(struct pipe_prt_msg
) -
374 sizeof(unsigned char) +
375 sizeof(SYNTHHID_PROTOCOL_REQUEST
),
376 (unsigned long)request
,
378 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
);
380 pr_err("unable to send SYNTHHID_PROTOCOL_REQUEST");
384 inputDevice
->protocol_wait_condition
= 0;
385 wait_event_timeout(inputDevice
->ProtocolWaitEvent
, inputDevice
->protocol_wait_condition
, msecs_to_jiffies(1000));
386 if (inputDevice
->protocol_wait_condition
== 0) {
391 response
= &inputDevice
->ProtocolResp
;
393 if (!response
->u
.Response
.Approved
) {
394 pr_err("SYNTHHID_PROTOCOL_REQUEST failed (version %d)",
395 SYNTHHID_INPUT_VERSION_DWORD
);
400 inputDevice
->device_wait_condition
= 0;
401 wait_event_timeout(inputDevice
->DeviceInfoWaitEvent
, inputDevice
->device_wait_condition
, msecs_to_jiffies(1000));
402 if (inputDevice
->device_wait_condition
== 0) {
408 * We should have gotten the device attr, hid desc and report
411 if (!inputDevice
->DeviceInfoStatus
)
412 pr_info("**** input channel up and running!! ****");
417 PutInputDevice(Device
);
426 * MousevscOnDeviceRemove()
429 * Callback when the our device is being removed
433 MousevscOnDeviceRemove(struct hv_device
*Device
)
435 struct mousevsc_dev
*inputDevice
;
438 pr_info("disabling input device (%p)...",
441 inputDevice
= ReleaseInputDevice(Device
);
445 * At this point, all outbound traffic should be disable. We only
446 * allow inbound traffic (responses) to proceed
448 * so that outstanding requests can be completed.
450 while (inputDevice
->NumOutstandingRequests
)
452 pr_info("waiting for %d requests to complete...", inputDevice
->NumOutstandingRequests
);
457 pr_info("removing input device (%p)...", Device
->ext
);
459 inputDevice
= FinalReleaseInputDevice(Device
);
461 pr_info("input device (%p) safe to remove", inputDevice
);
463 /* Close the channel */
464 vmbus_close(Device
->channel
);
466 FreeInputDevice(inputDevice
);
475 * MousevscOnCleanup()
478 * Perform any cleanup when the driver is removed
480 static void MousevscOnCleanup(struct hv_driver
*drv
)
486 MousevscOnSendCompletion(struct hv_device
*Device
,
487 struct vmpacket_descriptor
*Packet
)
489 struct mousevsc_dev
*inputDevice
;
492 inputDevice
= MustGetInputDevice(Device
);
494 pr_err("unable to get input device...device being destroyed?");
498 request
= (void*)(unsigned long *) Packet
->trans_id
;
500 if (request
== &inputDevice
->ProtocolReq
)
505 PutInputDevice(Device
);
509 MousevscOnReceiveDeviceInfo(
510 struct mousevsc_dev
* InputDevice
,
511 SYNTHHID_DEVICE_INFO
* DeviceInfo
515 struct hid_descriptor
*desc
;
516 struct mousevsc_prt_msg ack
;
518 /* Assume success for now */
519 InputDevice
->DeviceInfoStatus
= 0;
521 /* Save the device attr */
522 memcpy(&InputDevice
->DeviceAttr
, &DeviceInfo
->HidDeviceAttributes
, sizeof(struct input_dev_info
));
524 /* Save the hid desc */
525 desc
= (struct hid_descriptor
*)DeviceInfo
->HidDescriptorInformation
;
526 WARN_ON(desc
->bLength
> 0);
528 InputDevice
->HidDesc
= kzalloc(desc
->bLength
, GFP_KERNEL
);
530 if (!InputDevice
->HidDesc
) {
531 pr_err("unable to allocate hid descriptor - size %d", desc
->bLength
);
535 memcpy(InputDevice
->HidDesc
, desc
, desc
->bLength
);
537 /* Save the report desc */
538 InputDevice
->ReportDescSize
= desc
->desc
[0].wDescriptorLength
;
539 InputDevice
->ReportDesc
= kzalloc(InputDevice
->ReportDescSize
,
542 if (!InputDevice
->ReportDesc
) {
543 pr_err("unable to allocate report descriptor - size %d",
544 InputDevice
->ReportDescSize
);
548 memcpy(InputDevice
->ReportDesc
,
549 ((unsigned char *)desc
) + desc
->bLength
,
550 desc
->desc
[0].wDescriptorLength
);
553 memset(&ack
, sizeof(struct mousevsc_prt_msg
), 0);
555 ack
.PacketType
= PipeMessageData
;
556 ack
.DataSize
= sizeof(SYNTHHID_DEVICE_INFO_ACK
);
558 ack
.u
.Ack
.Header
.Type
= SynthHidInitialDeviceInfoAck
;
559 ack
.u
.Ack
.Header
.Size
= 1;
560 ack
.u
.Ack
.Reserved
= 0;
562 ret
= vmbus_sendpacket(InputDevice
->Device
->channel
,
564 sizeof(struct pipe_prt_msg
) - sizeof(unsigned char) + sizeof(SYNTHHID_DEVICE_INFO_ACK
),
567 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
);
569 pr_err("unable to send SYNTHHID_DEVICE_INFO_ACK - ret %d",
574 InputDevice
->device_wait_condition
= 1;
575 wake_up(&InputDevice
->DeviceInfoWaitEvent
);
580 if (InputDevice
->HidDesc
)
582 kfree(InputDevice
->HidDesc
);
583 InputDevice
->HidDesc
= NULL
;
586 if (InputDevice
->ReportDesc
)
588 kfree(InputDevice
->ReportDesc
);
589 InputDevice
->ReportDesc
= NULL
;
592 InputDevice
->DeviceInfoStatus
= -1;
593 InputDevice
->device_wait_condition
= 1;
594 wake_up(&InputDevice
->DeviceInfoWaitEvent
);
599 MousevscOnReceiveInputReport(
600 struct mousevsc_dev
* InputDevice
,
601 SYNTHHID_INPUT_REPORT
*InputReport
604 struct mousevsc_drv_obj
*inputDriver
;
606 if (!InputDevice
->bInitializeComplete
)
608 pr_info("Initialization incomplete...ignoring InputReport msg");
612 inputDriver
= (struct mousevsc_drv_obj
*)InputDevice
->Device
->drv
;
614 inputDriver
->OnInputReport(InputDevice
->Device
,
615 InputReport
->ReportBuffer
,
616 InputReport
->Header
.Size
);
620 MousevscOnReceive(struct hv_device
*Device
, struct vmpacket_descriptor
*Packet
)
622 struct pipe_prt_msg
*pipeMsg
;
623 SYNTHHID_MESSAGE
*hidMsg
;
624 struct mousevsc_dev
*inputDevice
;
626 inputDevice
= MustGetInputDevice(Device
);
629 pr_err("unable to get input device...device being destroyed?");
633 pipeMsg
= (struct pipe_prt_msg
*)((unsigned long)Packet
+ (Packet
->offset8
<< 3));
635 if (pipeMsg
->PacketType
!= PipeMessageData
) {
636 pr_err("unknown pipe msg type - type %d len %d",
637 pipeMsg
->PacketType
, pipeMsg
->DataSize
);
638 PutInputDevice(Device
);
642 hidMsg
= (SYNTHHID_MESSAGE
*)&pipeMsg
->Data
[0];
644 switch (hidMsg
->Header
.Type
) {
645 case SynthHidProtocolResponse
:
646 memcpy(&inputDevice
->ProtocolResp
, pipeMsg
, pipeMsg
->DataSize
+sizeof(struct pipe_prt_msg
) - sizeof(unsigned char));
647 inputDevice
->protocol_wait_condition
= 1;
648 wake_up(&inputDevice
->ProtocolWaitEvent
);
651 case SynthHidInitialDeviceInfo
:
652 WARN_ON(pipeMsg
->DataSize
>= sizeof(struct input_dev_info
));
655 * Parse out the device info into device attr,
656 * hid desc and report desc
658 MousevscOnReceiveDeviceInfo(inputDevice
,
659 (SYNTHHID_DEVICE_INFO
*)&pipeMsg
->Data
[0]);
661 case SynthHidInputReport
:
662 MousevscOnReceiveInputReport(inputDevice
,
663 (SYNTHHID_INPUT_REPORT
*)&pipeMsg
->Data
[0]);
667 pr_err("unsupported hid msg type - type %d len %d",
668 hidMsg
->Header
.Type
, hidMsg
->Header
.Size
);
672 PutInputDevice(Device
);
675 void MousevscOnChannelCallback(void *Context
)
677 const int packetSize
= 0x100;
679 struct hv_device
*device
= (struct hv_device
*)Context
;
680 struct mousevsc_dev
*inputDevice
;
684 unsigned char packet
[packetSize
];
685 struct vmpacket_descriptor
*desc
;
686 unsigned char *buffer
= packet
;
687 int bufferlen
= packetSize
;
689 inputDevice
= MustGetInputDevice(device
);
692 pr_err("unable to get input device...device being destroyed?");
697 ret
= vmbus_recvpacket_raw(device
->channel
, buffer
, bufferlen
, &bytesRecvd
, &requestId
);
700 if (bytesRecvd
> 0) {
701 desc
= (struct vmpacket_descriptor
*)buffer
;
706 MousevscOnSendCompletion(device
,
710 case VM_PKT_DATA_INBAND
:
711 MousevscOnReceive(device
, desc
);
715 pr_err("unhandled packet type %d, tid %llx len %d\n",
723 if (bufferlen
> packetSize
) {
727 bufferlen
= packetSize
;
731 * pr_debug("nothing else to read...");
734 if (bufferlen
> packetSize
) {
738 bufferlen
= packetSize
;
742 } else if (ret
== -2) {
743 /* Handle large packet */
744 bufferlen
= bytesRecvd
;
745 buffer
= kzalloc(bytesRecvd
, GFP_KERNEL
);
747 if (buffer
== NULL
) {
749 bufferlen
= packetSize
;
751 /* Try again next time around */
752 pr_err("unable to allocate buffer of size %d!",
759 PutInputDevice(device
);