1 #include <linux/types.h>
2 #include <linux/init.h>
3 #include <linux/delay.h>
4 #include <linux/slab.h>
5 #include <linux/console.h>
8 #include "hvc_console.h"
10 static int hvsi_send_packet(struct hvsi_priv
*pv
, struct hvsi_header
*packet
)
12 packet
->seqno
= atomic_inc_return(&pv
->seqno
);
14 /* Assumes that always succeeds, works in practice */
15 return pv
->put_chars(pv
->termno
, (char *)packet
, packet
->len
);
18 static void hvsi_start_handshake(struct hvsi_priv
*pv
)
24 atomic_set(&pv
->seqno
, 0);
26 pr_devel("HVSI@%x: Handshaking started\n", pv
->termno
);
28 /* Send version query */
29 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
30 q
.hdr
.len
= sizeof(struct hvsi_query
);
31 q
.verb
= VSV_SEND_VERSION_NUMBER
;
32 hvsi_send_packet(pv
, &q
.hdr
);
35 static int hvsi_send_close(struct hvsi_priv
*pv
)
37 struct hvsi_control ctrl
;
41 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
;
42 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
43 ctrl
.verb
= VSV_CLOSE_PROTOCOL
;
44 return hvsi_send_packet(pv
, &ctrl
.hdr
);
47 static void hvsi_cd_change(struct hvsi_priv
*pv
, int cd
)
50 pv
->mctrl
|= TIOCM_CD
;
52 pv
->mctrl
&= ~TIOCM_CD
;
54 /* We copy the existing hvsi driver semantics
55 * here which are to trigger a hangup when
56 * we get a carrier loss.
57 * Closing our connection to the server will
60 if (!pv
->is_console
&& pv
->opened
) {
61 pr_devel("HVSI@%x Carrier lost, hanging up !\n",
68 static void hvsi_got_control(struct hvsi_priv
*pv
)
70 struct hvsi_control
*pkt
= (struct hvsi_control
*)pv
->inbuf
;
73 case VSV_CLOSE_PROTOCOL
:
74 /* We restart the handshaking */
75 hvsi_start_handshake(pv
);
77 case VSV_MODEM_CTL_UPDATE
:
78 /* Transition of carrier detect */
79 hvsi_cd_change(pv
, pkt
->word
& HVSI_TSCD
);
84 static void hvsi_got_query(struct hvsi_priv
*pv
)
86 struct hvsi_query
*pkt
= (struct hvsi_query
*)pv
->inbuf
;
87 struct hvsi_query_response r
;
89 /* We only handle version queries */
90 if (pkt
->verb
!= VSV_SEND_VERSION_NUMBER
)
93 pr_devel("HVSI@%x: Got version query, sending response...\n",
96 /* Send version response */
97 r
.hdr
.type
= VS_QUERY_RESPONSE_PACKET_HEADER
;
98 r
.hdr
.len
= sizeof(struct hvsi_query_response
);
99 r
.verb
= VSV_SEND_VERSION_NUMBER
;
100 r
.u
.version
= HVSI_VERSION
;
101 r
.query_seqno
= pkt
->hdr
.seqno
;
102 hvsi_send_packet(pv
, &r
.hdr
);
104 /* Assume protocol is open now */
108 static void hvsi_got_response(struct hvsi_priv
*pv
)
110 struct hvsi_query_response
*r
=
111 (struct hvsi_query_response
*)pv
->inbuf
;
114 case VSV_SEND_MODEM_CTL_STATUS
:
115 hvsi_cd_change(pv
, r
->u
.mctrl_word
& HVSI_TSCD
);
116 pv
->mctrl_update
= 1;
121 static int hvsi_check_packet(struct hvsi_priv
*pv
)
125 /* Check header validity. If it's invalid, we ditch
126 * the whole buffer and hope we eventually resync
128 if (pv
->inbuf
[0] < 0xfc) {
129 pv
->inbuf_len
= pv
->inbuf_pktlen
= 0;
135 /* Packet incomplete ? */
136 if (pv
->inbuf_len
< len
)
139 pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
140 pv
->termno
, type
, len
);
142 /* We have a packet, yay ! Handle it */
144 case VS_DATA_PACKET_HEADER
:
145 pv
->inbuf_pktlen
= len
- 4;
148 case VS_CONTROL_PACKET_HEADER
:
149 hvsi_got_control(pv
);
151 case VS_QUERY_PACKET_HEADER
:
154 case VS_QUERY_RESPONSE_PACKET_HEADER
:
155 hvsi_got_response(pv
);
159 /* Swallow packet and retry */
160 pv
->inbuf_len
-= len
;
161 memmove(pv
->inbuf
, &pv
->inbuf
[len
], pv
->inbuf_len
);
165 static int hvsi_get_packet(struct hvsi_priv
*pv
)
167 /* If we have room in the buffer, ask HV for more */
168 if (pv
->inbuf_len
< HVSI_INBUF_SIZE
)
169 pv
->inbuf_len
+= pv
->get_chars(pv
->termno
,
170 &pv
->inbuf
[pv
->inbuf_len
],
171 HVSI_INBUF_SIZE
- pv
->inbuf_len
);
173 * If we have at least 4 bytes in the buffer, check for
174 * a full packet and retry
176 if (pv
->inbuf_len
>= 4)
177 return hvsi_check_packet(pv
);
181 int hvsilib_get_chars(struct hvsi_priv
*pv
, char *buf
, int count
)
183 unsigned int tries
, read
= 0;
188 /* If we aren't open, don't do anything in order to avoid races
189 * with connection establishment. The hvc core will call this
190 * before we have returned from notifier_add(), and we need to
191 * avoid multiple users playing with the receive buffer
196 /* We try twice, once with what data we have and once more
197 * after we try to fetch some more from the hypervisor
199 for (tries
= 1; count
&& tries
< 2; tries
++) {
200 /* Consume existing data packet */
201 if (pv
->inbuf_pktlen
) {
202 unsigned int l
= min(count
, (int)pv
->inbuf_pktlen
);
203 memcpy(&buf
[read
], &pv
->inbuf
[pv
->inbuf_cur
], l
);
205 pv
->inbuf_pktlen
-= l
;
212 /* Data packet fully consumed, move down remaning data */
214 pv
->inbuf_len
-= pv
->inbuf_cur
;
215 memmove(pv
->inbuf
, &pv
->inbuf
[pv
->inbuf_cur
],
220 /* Try to get another packet */
221 if (hvsi_get_packet(pv
))
224 if (!pv
->established
) {
225 pr_devel("HVSI@%x: returning -EPIPE\n", pv
->termno
);
231 int hvsilib_put_chars(struct hvsi_priv
*pv
, const char *buf
, int count
)
234 int rc
, adjcount
= min(count
, HVSI_MAX_OUTGOING_DATA
);
239 dp
.hdr
.type
= VS_DATA_PACKET_HEADER
;
240 dp
.hdr
.len
= adjcount
+ sizeof(struct hvsi_header
);
241 memcpy(dp
.data
, buf
, adjcount
);
242 rc
= hvsi_send_packet(pv
, &dp
.hdr
);
248 static void maybe_msleep(unsigned long ms
)
250 /* During early boot, IRQs are disabled, use mdelay */
257 int hvsilib_read_mctrl(struct hvsi_priv
*pv
)
262 pr_devel("HVSI@%x: Querying modem control status...\n",
265 pv
->mctrl_update
= 0;
266 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
267 q
.hdr
.len
= sizeof(struct hvsi_query
);
268 q
.hdr
.seqno
= atomic_inc_return(&pv
->seqno
);
269 q
.verb
= VSV_SEND_MODEM_CTL_STATUS
;
270 rc
= hvsi_send_packet(pv
, &q
.hdr
);
272 pr_devel("HVSI@%x: Error %d...\n", pv
->termno
, rc
);
276 /* Try for up to 200ms */
277 for (timeout
= 0; timeout
< 20; timeout
++) {
278 if (!pv
->established
)
280 if (pv
->mctrl_update
)
282 if (!hvsi_get_packet(pv
))
288 int hvsilib_write_mctrl(struct hvsi_priv
*pv
, int dtr
)
290 struct hvsi_control ctrl
;
291 unsigned short mctrl
;
298 if (mctrl
== pv
->mctrl
)
302 pr_devel("HVSI@%x: %s DTR...\n", pv
->termno
,
303 dtr
? "Setting" : "Clearing");
305 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
,
306 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
307 ctrl
.verb
= VSV_SET_MODEM_CTL
;
308 ctrl
.mask
= HVSI_TSDTR
;
309 ctrl
.word
= dtr
? HVSI_TSDTR
: 0;
310 return hvsi_send_packet(pv
, &ctrl
.hdr
);
313 void hvsilib_establish(struct hvsi_priv
*pv
)
317 pr_devel("HVSI@%x: Establishing...\n", pv
->termno
);
319 /* Try for up to 200ms, there can be a packet to
320 * start the process waiting for us...
322 for (timeout
= 0; timeout
< 20; timeout
++) {
325 if (!hvsi_get_packet(pv
))
329 /* Failed, send a close connection packet just
332 pr_devel("HVSI@%x: ... sending close\n", pv
->termno
);
336 /* Then restart handshake */
338 pr_devel("HVSI@%x: ... restarting handshake\n", pv
->termno
);
340 hvsi_start_handshake(pv
);
342 pr_devel("HVSI@%x: ... waiting handshake\n", pv
->termno
);
344 /* Try for up to 200s */
345 for (timeout
= 0; timeout
< 20; timeout
++) {
348 if (!hvsi_get_packet(pv
))
352 if (!pv
->established
) {
353 pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
358 /* Query modem control lines */
360 pr_devel("HVSI@%x: ... established, reading mctrl\n", pv
->termno
);
362 hvsilib_read_mctrl(pv
);
364 /* Set our own DTR */
366 pr_devel("HVSI@%x: ... setting mctrl\n", pv
->termno
);
368 hvsilib_write_mctrl(pv
, 1);
370 /* Set the opened flag so reads are allowed */
375 int hvsilib_open(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
377 pr_devel("HVSI@%x: open !\n", pv
->termno
);
379 /* Keep track of the tty data structure */
380 pv
->tty
= tty_kref_get(hp
->tty
);
382 hvsilib_establish(pv
);
387 void hvsilib_close(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
391 pr_devel("HVSI@%x: close !\n", pv
->termno
);
393 if (!pv
->is_console
) {
394 pr_devel("HVSI@%x: Not a console, tearing down\n",
397 /* Clear opened, synchronize with khvcd */
398 spin_lock_irqsave(&hp
->lock
, flags
);
400 spin_unlock_irqrestore(&hp
->lock
, flags
);
402 /* Clear our own DTR */
403 if (!pv
->tty
|| (pv
->tty
->termios
->c_cflag
& HUPCL
))
404 hvsilib_write_mctrl(pv
, 0);
406 /* Tear down the connection */
411 tty_kref_put(pv
->tty
);
415 void hvsilib_init(struct hvsi_priv
*pv
,
416 int (*get_chars
)(uint32_t termno
, char *buf
, int count
),
417 int (*put_chars
)(uint32_t termno
, const char *buf
,
419 int termno
, int is_console
)
421 memset(pv
, 0, sizeof(*pv
));
422 pv
->get_chars
= get_chars
;
423 pv
->put_chars
= put_chars
;
425 pv
->is_console
= is_console
;