summaryrefslogtreecommitdiff
path: root/minix/lib/libhgfs/channel.c
blob: 985e842934bbcaaaff27749dd4dc1b48c17a3eba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* 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;
}