minix3/lib/libhgfs/channel.c

151 lines
3.7 KiB
C

/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
#include "inc.h"
#define CMD_XFER 0x1E /* vmware backdoor transfer command */
enum {
XFER_OPEN, /* open transfer channel */
XFER_SENDLEN, /* specify length of data to send */
XFER_SEND, /* send data */
XFER_RECVLEN, /* get length of data to receive */
XFER_RECV, /* receive data */
XFER_RECVACK, /* acknowledge receipt of data */
XFER_CLOSE /* close transfer channel */
};
#define STATUS(p) (HIWORD((p)[2]) & 0xff)
/*===========================================================================*
* channel_open *
*===========================================================================*/
int channel_open(
struct channel *ch, /* struct describing the new channel */
u32_t type /* channel type: CH_IN or CH_OUT */
)
{
/* Open a new backdoor channel. Upon success, the given channel structure will
* be filled with information and can be used in subsequent channel calls.
* Return OK on success, or a negative error code on error.
*/
u32_t ptr[6];
ptr[1] = type | 0x80000000;
ptr[2] = MAKELONG(CMD_XFER, XFER_OPEN);
backdoor(ptr);
if ((STATUS(ptr) & 1) == 0) return EIO;
ch->id = HIWORD(ptr[3]);
ch->cookie1 = ptr[4];
ch->cookie2 = ptr[5];
return OK;
}
/*===========================================================================*
* channel_close *
*===========================================================================*/
void channel_close(
struct channel *ch /* backdoor channel to close */
)
{
/* Close a previously opened backdoor channel.
*/
u32_t ptr[6];
ptr[2] = MAKELONG(CMD_XFER, XFER_CLOSE);
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = ch->cookie1;
ptr[5] = ch->cookie2;
backdoor(ptr);
}
/*===========================================================================*
* channel_send *
*===========================================================================*/
int channel_send(
struct channel *ch, /* backdoor channel to send to */
char *buf, /* buffer to send data from */
int len /* size of the data to send */
)
{
/* Receive data over a backdoor channel. Return OK on success, or a negative
* error code on error.
*/
u32_t ptr[7];
ptr[1] = len;
ptr[2] = MAKELONG(CMD_XFER, XFER_SENDLEN);
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = ch->cookie1;
ptr[5] = ch->cookie2;
backdoor(ptr);
if ((STATUS(ptr) & 1) == 0) return EIO;
if (len == 0) return OK;
ptr[1] = MAKELONG(0, 1);
ptr[2] = len;
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = (u32_t)buf;
ptr[5] = ch->cookie2;
ptr[6] = ch->cookie1;
backdoor_out(ptr);
return OK;
}
/*===========================================================================*
* channel_recv *
*===========================================================================*/
int channel_recv(
struct channel *ch, /* backdoor channel to receive from */
char *buf, /* buffer to receive data into */
int max /* size of the buffer */
)
{
/* Receive data on a backdoor channel. Return the number of bytes received, or
* a negative error code on error.
*/
u32_t ptr[7];
int len;
ptr[2] = MAKELONG(CMD_XFER, XFER_RECVLEN);
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = ch->cookie1;
ptr[5] = ch->cookie2;
backdoor(ptr);
if ((STATUS(ptr) & 0x81) == 0) return EIO;
if ((len = ptr[1]) == 0 || (STATUS(ptr) & 3) == 1) return 0;
if (len > max) return E2BIG;
ptr[1] = MAKELONG(0, 1);
ptr[2] = len;
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = ch->cookie1;
ptr[5] = (u32_t)buf;
ptr[6] = ch->cookie2;
backdoor_in(ptr);
ptr[1] = 1;
ptr[2] = MAKELONG(CMD_XFER, XFER_RECVACK);
ptr[3] = MAKELONG(0, ch->id);
ptr[4] = ch->cookie1;
ptr[5] = ch->cookie2;
backdoor(ptr);
return len;
}