101325476SK. Y. Srinivasan /* 201325476SK. Y. Srinivasan * An implementation of file copy service. 301325476SK. Y. Srinivasan * 401325476SK. Y. Srinivasan * Copyright (C) 2014, Microsoft, Inc. 501325476SK. Y. Srinivasan * 601325476SK. Y. Srinivasan * Author : K. Y. Srinivasan <ksrinivasan@novell.com> 701325476SK. Y. Srinivasan * 801325476SK. Y. Srinivasan * This program is free software; you can redistribute it and/or modify it 901325476SK. Y. Srinivasan * under the terms of the GNU General Public License version 2 as published 1001325476SK. Y. Srinivasan * by the Free Software Foundation. 1101325476SK. Y. Srinivasan * 1201325476SK. Y. Srinivasan * This program is distributed in the hope that it will be useful, but 1301325476SK. Y. Srinivasan * WITHOUT ANY WARRANTY; without even the implied warranty of 1401325476SK. Y. Srinivasan * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 1501325476SK. Y. Srinivasan * NON INFRINGEMENT. See the GNU General Public License for more 1601325476SK. Y. Srinivasan * details. 1701325476SK. Y. Srinivasan * 1801325476SK. Y. Srinivasan */ 1901325476SK. Y. Srinivasan 2001325476SK. Y. Srinivasan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2101325476SK. Y. Srinivasan 2201325476SK. Y. Srinivasan #include <linux/nls.h> 2301325476SK. Y. Srinivasan #include <linux/workqueue.h> 2401325476SK. Y. Srinivasan #include <linux/hyperv.h> 2501325476SK. Y. Srinivasan #include <linux/sched.h> 2601325476SK. Y. Srinivasan 2701325476SK. Y. Srinivasan #include "hyperv_vmbus.h" 28c7e490fcSVitaly Kuznetsov #include "hv_utils_transport.h" 2901325476SK. Y. Srinivasan 3001325476SK. Y. Srinivasan #define WIN8_SRV_MAJOR 1 3101325476SK. Y. Srinivasan #define WIN8_SRV_MINOR 1 3201325476SK. Y. Srinivasan #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) 3301325476SK. Y. Srinivasan 34a1656454SAlex Ng #define FCOPY_VER_COUNT 1 35a1656454SAlex Ng static const int fcopy_versions[] = { 36a1656454SAlex Ng WIN8_SRV_VERSION 37a1656454SAlex Ng }; 38a1656454SAlex Ng 39a1656454SAlex Ng #define FW_VER_COUNT 1 40a1656454SAlex Ng static const int fw_versions[] = { 41a1656454SAlex Ng UTIL_FW_VERSION 42a1656454SAlex Ng }; 43a1656454SAlex Ng 4401325476SK. Y. Srinivasan /* 4501325476SK. Y. Srinivasan * Global state maintained for transaction that is being processed. 4601325476SK. Y. Srinivasan * For a class of integration services, including the "file copy service", 4701325476SK. Y. Srinivasan * the specified protocol is a "request/response" protocol which means that 4801325476SK. Y. Srinivasan * there can only be single outstanding transaction from the host at any 4901325476SK. Y. Srinivasan * given point in time. We use this to simplify memory management in this 5001325476SK. Y. Srinivasan * driver - we cache and process only one message at a time. 5101325476SK. Y. Srinivasan * 5201325476SK. Y. Srinivasan * While the request/response protocol is guaranteed by the host, we further 5301325476SK. Y. Srinivasan * ensure this by serializing packet processing in this driver - we do not 5401325476SK. Y. Srinivasan * read additional packets from the VMBUs until the current packet is fully 5501325476SK. Y. Srinivasan * handled. 5601325476SK. Y. Srinivasan */ 5701325476SK. Y. Srinivasan 5801325476SK. Y. Srinivasan static struct { 594c93ccccSVitaly Kuznetsov int state; /* hvutil_device_state */ 6001325476SK. Y. Srinivasan int recv_len; /* number of bytes received. */ 6101325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; /* current message */ 6201325476SK. Y. Srinivasan struct vmbus_channel *recv_channel; /* chn we got the request */ 6301325476SK. Y. Srinivasan u64 recv_req_id; /* request ID. */ 6401325476SK. Y. Srinivasan } fcopy_transaction; 6501325476SK. Y. Srinivasan 6601325476SK. Y. Srinivasan static void fcopy_respond_to_host(int error); 67c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy); 681d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy); 691d072339SVitaly Kuznetsov static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func); 70c7e490fcSVitaly Kuznetsov static DECLARE_WORK(fcopy_send_work, fcopy_send_data); 71c7e490fcSVitaly Kuznetsov static const char fcopy_devname[] = "vmbus/hv_fcopy"; 7201325476SK. Y. Srinivasan static u8 *recv_buffer; 73c7e490fcSVitaly Kuznetsov static struct hvutil_transport *hvt; 7420951c75SK. Y. Srinivasan static struct completion release_event; 75a4d1ee5bSVitaly Kuznetsov /* 76a4d1ee5bSVitaly Kuznetsov * This state maintains the version number registered by the daemon. 77a4d1ee5bSVitaly Kuznetsov */ 78a4d1ee5bSVitaly Kuznetsov static int dm_reg_value; 7901325476SK. Y. Srinivasan 803cace4a6SOlaf Hering static void fcopy_poll_wrapper(void *channel) 813cace4a6SOlaf Hering { 823cace4a6SOlaf Hering /* Transaction is finished, reset the state here to avoid races. */ 833cace4a6SOlaf Hering fcopy_transaction.state = HVUTIL_READY; 843cace4a6SOlaf Hering hv_fcopy_onchannelcallback(channel); 853cace4a6SOlaf Hering } 863cace4a6SOlaf Hering 871d072339SVitaly Kuznetsov static void fcopy_timeout_func(struct work_struct *dummy) 8801325476SK. Y. Srinivasan { 8901325476SK. Y. Srinivasan /* 9001325476SK. Y. Srinivasan * If the timer fires, the user-mode component has not responded; 9101325476SK. Y. Srinivasan * process the pending transaction. 9201325476SK. Y. Srinivasan */ 9301325476SK. Y. Srinivasan fcopy_respond_to_host(HV_E_FAIL); 943cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); 9501325476SK. Y. Srinivasan } 9601325476SK. Y. Srinivasan 97e0fa3e5eSVitaly Kuznetsov static void fcopy_register_done(void) 98e0fa3e5eSVitaly Kuznetsov { 99e0fa3e5eSVitaly Kuznetsov pr_debug("FCP: userspace daemon registered\n"); 100e0fa3e5eSVitaly Kuznetsov hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); 101e0fa3e5eSVitaly Kuznetsov } 102e0fa3e5eSVitaly Kuznetsov 10301325476SK. Y. Srinivasan static int fcopy_handle_handshake(u32 version) 10401325476SK. Y. Srinivasan { 105a4d1ee5bSVitaly Kuznetsov u32 our_ver = FCOPY_CURRENT_VERSION; 106a4d1ee5bSVitaly Kuznetsov 10701325476SK. Y. Srinivasan switch (version) { 108a4d1ee5bSVitaly Kuznetsov case FCOPY_VERSION_0: 109a4d1ee5bSVitaly Kuznetsov /* Daemon doesn't expect us to reply */ 110a4d1ee5bSVitaly Kuznetsov dm_reg_value = version; 111a4d1ee5bSVitaly Kuznetsov break; 112a4d1ee5bSVitaly Kuznetsov case FCOPY_VERSION_1: 113a4d1ee5bSVitaly Kuznetsov /* Daemon expects us to reply with our own version */ 114e0fa3e5eSVitaly Kuznetsov if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), 115e0fa3e5eSVitaly Kuznetsov fcopy_register_done)) 116a4d1ee5bSVitaly Kuznetsov return -EFAULT; 117a4d1ee5bSVitaly Kuznetsov dm_reg_value = version; 11801325476SK. Y. Srinivasan break; 11901325476SK. Y. Srinivasan default: 12001325476SK. Y. Srinivasan /* 12101325476SK. Y. Srinivasan * For now we will fail the registration. 12201325476SK. Y. Srinivasan * If and when we have multiple versions to 12301325476SK. Y. Srinivasan * deal with, we will be backward compatible. 12401325476SK. Y. Srinivasan * We will add this code when needed. 12501325476SK. Y. Srinivasan */ 12601325476SK. Y. Srinivasan return -EINVAL; 12701325476SK. Y. Srinivasan } 128e0fa3e5eSVitaly Kuznetsov pr_debug("FCP: userspace daemon ver. %d connected\n", version); 12901325476SK. Y. Srinivasan return 0; 13001325476SK. Y. Srinivasan } 13101325476SK. Y. Srinivasan 132c7e490fcSVitaly Kuznetsov static void fcopy_send_data(struct work_struct *dummy) 13301325476SK. Y. Srinivasan { 13425ef06feSVitaly Kuznetsov struct hv_start_fcopy *smsg_out = NULL; 13501325476SK. Y. Srinivasan int operation = fcopy_transaction.fcopy_msg->operation; 13601325476SK. Y. Srinivasan struct hv_start_fcopy *smsg_in; 137c7e490fcSVitaly Kuznetsov void *out_src; 138c7e490fcSVitaly Kuznetsov int rc, out_len; 13901325476SK. Y. Srinivasan 14001325476SK. Y. Srinivasan /* 14101325476SK. Y. Srinivasan * The strings sent from the host are encoded in 14201325476SK. Y. Srinivasan * in utf16; convert it to utf8 strings. 14301325476SK. Y. Srinivasan * The host assures us that the utf16 strings will not exceed 14401325476SK. Y. Srinivasan * the max lengths specified. We will however, reserve room 14501325476SK. Y. Srinivasan * for the string terminating character - in the utf16s_utf8s() 14601325476SK. Y. Srinivasan * function we limit the size of the buffer where the converted 14701325476SK. Y. Srinivasan * string is placed to W_MAX_PATH -1 to guarantee 14801325476SK. Y. Srinivasan * that the strings can be properly terminated! 14901325476SK. Y. Srinivasan */ 15001325476SK. Y. Srinivasan 15101325476SK. Y. Srinivasan switch (operation) { 15201325476SK. Y. Srinivasan case START_FILE_COPY: 153c7e490fcSVitaly Kuznetsov out_len = sizeof(struct hv_start_fcopy); 15425ef06feSVitaly Kuznetsov smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL); 15525ef06feSVitaly Kuznetsov if (!smsg_out) 15625ef06feSVitaly Kuznetsov return; 15725ef06feSVitaly Kuznetsov 15825ef06feSVitaly Kuznetsov smsg_out->hdr.operation = operation; 15901325476SK. Y. Srinivasan smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; 16001325476SK. Y. Srinivasan 16101325476SK. Y. Srinivasan utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, 16201325476SK. Y. Srinivasan UTF16_LITTLE_ENDIAN, 16325ef06feSVitaly Kuznetsov (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1); 16401325476SK. Y. Srinivasan 16501325476SK. Y. Srinivasan utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, 16601325476SK. Y. Srinivasan UTF16_LITTLE_ENDIAN, 16725ef06feSVitaly Kuznetsov (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1); 16801325476SK. Y. Srinivasan 16925ef06feSVitaly Kuznetsov smsg_out->copy_flags = smsg_in->copy_flags; 17025ef06feSVitaly Kuznetsov smsg_out->file_size = smsg_in->file_size; 17125ef06feSVitaly Kuznetsov out_src = smsg_out; 17201325476SK. Y. Srinivasan break; 17301325476SK. Y. Srinivasan 17401325476SK. Y. Srinivasan default: 175c7e490fcSVitaly Kuznetsov out_src = fcopy_transaction.fcopy_msg; 176c7e490fcSVitaly Kuznetsov out_len = fcopy_transaction.recv_len; 17701325476SK. Y. Srinivasan break; 17801325476SK. Y. Srinivasan } 179c7e490fcSVitaly Kuznetsov 180c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_REQ; 181e0fa3e5eSVitaly Kuznetsov rc = hvutil_transport_send(hvt, out_src, out_len, NULL); 182c7e490fcSVitaly Kuznetsov if (rc) { 183c7e490fcSVitaly Kuznetsov pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); 184c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 185c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 186c7e490fcSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_READY; 187c7e490fcSVitaly Kuznetsov } 188c7e490fcSVitaly Kuznetsov } 18925ef06feSVitaly Kuznetsov kfree(smsg_out); 19025ef06feSVitaly Kuznetsov 19101325476SK. Y. Srinivasan return; 19201325476SK. Y. Srinivasan } 19301325476SK. Y. Srinivasan 19401325476SK. Y. Srinivasan /* 19501325476SK. Y. Srinivasan * Send a response back to the host. 19601325476SK. Y. Srinivasan */ 19701325476SK. Y. Srinivasan 19801325476SK. Y. Srinivasan static void 19901325476SK. Y. Srinivasan fcopy_respond_to_host(int error) 20001325476SK. Y. Srinivasan { 20101325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 20201325476SK. Y. Srinivasan u32 buf_len; 20301325476SK. Y. Srinivasan struct vmbus_channel *channel; 20401325476SK. Y. Srinivasan u64 req_id; 20501325476SK. Y. Srinivasan 20601325476SK. Y. Srinivasan /* 20701325476SK. Y. Srinivasan * Copy the global state for completing the transaction. Note that 20801325476SK. Y. Srinivasan * only one transaction can be active at a time. This is guaranteed 20901325476SK. Y. Srinivasan * by the file copy protocol implemented by the host. Furthermore, 21001325476SK. Y. Srinivasan * the "transaction active" state we maintain ensures that there can 21101325476SK. Y. Srinivasan * only be one active transaction at a time. 21201325476SK. Y. Srinivasan */ 21301325476SK. Y. Srinivasan 21401325476SK. Y. Srinivasan buf_len = fcopy_transaction.recv_len; 21501325476SK. Y. Srinivasan channel = fcopy_transaction.recv_channel; 21601325476SK. Y. Srinivasan req_id = fcopy_transaction.recv_req_id; 21701325476SK. Y. Srinivasan 21801325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *) 21901325476SK. Y. Srinivasan &recv_buffer[sizeof(struct vmbuspipe_hdr)]; 22001325476SK. Y. Srinivasan 22101325476SK. Y. Srinivasan if (channel->onchannel_callback == NULL) 22201325476SK. Y. Srinivasan /* 22301325476SK. Y. Srinivasan * We have raced with util driver being unloaded; 22401325476SK. Y. Srinivasan * silently return. 22501325476SK. Y. Srinivasan */ 22601325476SK. Y. Srinivasan return; 22701325476SK. Y. Srinivasan 22801325476SK. Y. Srinivasan icmsghdr->status = error; 22901325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 23001325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, 23101325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 23201325476SK. Y. Srinivasan } 23301325476SK. Y. Srinivasan 23401325476SK. Y. Srinivasan void hv_fcopy_onchannelcallback(void *context) 23501325476SK. Y. Srinivasan { 23601325476SK. Y. Srinivasan struct vmbus_channel *channel = context; 23701325476SK. Y. Srinivasan u32 recvlen; 23801325476SK. Y. Srinivasan u64 requestid; 23901325476SK. Y. Srinivasan struct hv_fcopy_hdr *fcopy_msg; 24001325476SK. Y. Srinivasan struct icmsg_hdr *icmsghdr; 24101325476SK. Y. Srinivasan int fcopy_srv_version; 24201325476SK. Y. Srinivasan 2433cace4a6SOlaf Hering if (fcopy_transaction.state > HVUTIL_READY) 24401325476SK. Y. Srinivasan return; 24501325476SK. Y. Srinivasan 24601325476SK. Y. Srinivasan vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, 24701325476SK. Y. Srinivasan &requestid); 24801325476SK. Y. Srinivasan if (recvlen <= 0) 24901325476SK. Y. Srinivasan return; 25001325476SK. Y. Srinivasan 25101325476SK. Y. Srinivasan icmsghdr = (struct icmsg_hdr *)&recv_buffer[ 25201325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr)]; 25301325476SK. Y. Srinivasan if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) { 254a1656454SAlex Ng vmbus_prep_negotiate_resp(icmsghdr, recv_buffer, 255a1656454SAlex Ng fw_versions, FW_VER_COUNT, 256a1656454SAlex Ng fcopy_versions, FCOPY_VER_COUNT, 257a1656454SAlex Ng NULL, &fcopy_srv_version); 25801325476SK. Y. Srinivasan } else { 25901325476SK. Y. Srinivasan fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ 26001325476SK. Y. Srinivasan sizeof(struct vmbuspipe_hdr) + 26101325476SK. Y. Srinivasan sizeof(struct icmsg_hdr)]; 26201325476SK. Y. Srinivasan 26301325476SK. Y. Srinivasan /* 26401325476SK. Y. Srinivasan * Stash away this global state for completing the 26501325476SK. Y. Srinivasan * transaction; note transactions are serialized. 26601325476SK. Y. Srinivasan */ 26701325476SK. Y. Srinivasan 26801325476SK. Y. Srinivasan fcopy_transaction.recv_len = recvlen; 26901325476SK. Y. Srinivasan fcopy_transaction.recv_req_id = requestid; 27001325476SK. Y. Srinivasan fcopy_transaction.fcopy_msg = fcopy_msg; 27101325476SK. Y. Srinivasan 2724c93ccccSVitaly Kuznetsov if (fcopy_transaction.state < HVUTIL_READY) { 2734c93ccccSVitaly Kuznetsov /* Userspace is not registered yet */ 2744c93ccccSVitaly Kuznetsov fcopy_respond_to_host(HV_E_FAIL); 2754c93ccccSVitaly Kuznetsov return; 2764c93ccccSVitaly Kuznetsov } 2774c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED; 2784c93ccccSVitaly Kuznetsov 27901325476SK. Y. Srinivasan /* 28001325476SK. Y. Srinivasan * Send the information to the user-level daemon. 28101325476SK. Y. Srinivasan */ 282c7e490fcSVitaly Kuznetsov schedule_work(&fcopy_send_work); 283c0b200cfSK. Y. Srinivasan schedule_delayed_work(&fcopy_timeout_work, 284c0b200cfSK. Y. Srinivasan HV_UTIL_TIMEOUT * HZ); 28501325476SK. Y. Srinivasan return; 28601325476SK. Y. Srinivasan } 28701325476SK. Y. Srinivasan icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; 28801325476SK. Y. Srinivasan vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, 28901325476SK. Y. Srinivasan VM_PKT_DATA_INBAND, 0); 29001325476SK. Y. Srinivasan } 29101325476SK. Y. Srinivasan 292c7e490fcSVitaly Kuznetsov /* Callback when data is received from userspace */ 293c7e490fcSVitaly Kuznetsov static int fcopy_on_msg(void *msg, int len) 29401325476SK. Y. Srinivasan { 295c7e490fcSVitaly Kuznetsov int *val = (int *)msg; 29601325476SK. Y. Srinivasan 297c7e490fcSVitaly Kuznetsov if (len != sizeof(int)) 29801325476SK. Y. Srinivasan return -EINVAL; 29901325476SK. Y. Srinivasan 300c7e490fcSVitaly Kuznetsov if (fcopy_transaction.state == HVUTIL_DEVICE_INIT) 301c7e490fcSVitaly Kuznetsov return fcopy_handle_handshake(*val); 30201325476SK. Y. Srinivasan 3034c93ccccSVitaly Kuznetsov if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ) 3044c93ccccSVitaly Kuznetsov return -EINVAL; 3054c93ccccSVitaly Kuznetsov 30601325476SK. Y. Srinivasan /* 30701325476SK. Y. Srinivasan * Complete the transaction by forwarding the result 30801325476SK. Y. Srinivasan * to the host. But first, cancel the timeout. 30901325476SK. Y. Srinivasan */ 3104c93ccccSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) { 3114c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_USERSPACE_RECV; 312c7e490fcSVitaly Kuznetsov fcopy_respond_to_host(*val); 3133cace4a6SOlaf Hering hv_poll_channel(fcopy_transaction.recv_channel, 3143cace4a6SOlaf Hering fcopy_poll_wrapper); 315242f3122SVitaly Kuznetsov } 31601325476SK. Y. Srinivasan 31701325476SK. Y. Srinivasan return 0; 31801325476SK. Y. Srinivasan } 31901325476SK. Y. Srinivasan 320c7e490fcSVitaly Kuznetsov static void fcopy_on_reset(void) 32101325476SK. Y. Srinivasan { 32201325476SK. Y. Srinivasan /* 32301325476SK. Y. Srinivasan * The daemon has exited; reset the state. 32401325476SK. Y. Srinivasan */ 3254c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 326d9b16529SDexuan Cui 327c7e490fcSVitaly Kuznetsov if (cancel_delayed_work_sync(&fcopy_timeout_work)) 328d9b16529SDexuan Cui fcopy_respond_to_host(HV_E_FAIL); 32920951c75SK. Y. Srinivasan complete(&release_event); 330d9b16529SDexuan Cui } 33101325476SK. Y. Srinivasan 33201325476SK. Y. Srinivasan int hv_fcopy_init(struct hv_util_service *srv) 33301325476SK. Y. Srinivasan { 33401325476SK. Y. Srinivasan recv_buffer = srv->recv_buffer; 335b9830d12SK. Y. Srinivasan fcopy_transaction.recv_channel = srv->channel; 33601325476SK. Y. Srinivasan 33720951c75SK. Y. Srinivasan init_completion(&release_event); 33801325476SK. Y. Srinivasan /* 33901325476SK. Y. Srinivasan * When this driver loads, the user level daemon that 34001325476SK. Y. Srinivasan * processes the host requests may not yet be running. 34101325476SK. Y. Srinivasan * Defer processing channel callbacks until the daemon 34201325476SK. Y. Srinivasan * has registered. 34301325476SK. Y. Srinivasan */ 3444c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_INIT; 34501325476SK. Y. Srinivasan 346c7e490fcSVitaly Kuznetsov hvt = hvutil_transport_init(fcopy_devname, 0, 0, 347c7e490fcSVitaly Kuznetsov fcopy_on_msg, fcopy_on_reset); 348c7e490fcSVitaly Kuznetsov if (!hvt) 349c7e490fcSVitaly Kuznetsov return -EFAULT; 350c7e490fcSVitaly Kuznetsov 351c7e490fcSVitaly Kuznetsov return 0; 35201325476SK. Y. Srinivasan } 35301325476SK. Y. Srinivasan 35401325476SK. Y. Srinivasan void hv_fcopy_deinit(void) 35501325476SK. Y. Srinivasan { 3564c93ccccSVitaly Kuznetsov fcopy_transaction.state = HVUTIL_DEVICE_DYING; 3571d072339SVitaly Kuznetsov cancel_delayed_work_sync(&fcopy_timeout_work); 358c7e490fcSVitaly Kuznetsov hvutil_transport_destroy(hvt); 35920951c75SK. Y. Srinivasan wait_for_completion(&release_event); 36001325476SK. Y. Srinivasan } 361