1 #include <linux/types.h>
2 #include <linux/delay.h>
3 #include <linux/slab.h>
4 #include <linux/console.h>
7 #include "hvc_console.h"
9 static int hvsi_send_packet(struct hvsi_priv
*pv
, struct hvsi_header
*packet
)
11 packet
->seqno
= cpu_to_be16(atomic_inc_return(&pv
->seqno
));
13 /* Assumes that always succeeds, works in practice */
14 return pv
->put_chars(pv
->termno
, (char *)packet
, packet
->len
);
17 static void hvsi_start_handshake(struct hvsi_priv
*pv
)
23 atomic_set(&pv
->seqno
, 0);
25 pr_devel("HVSI@%x: Handshaking started\n", pv
->termno
);
27 /* Send version query */
28 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
29 q
.hdr
.len
= sizeof(struct hvsi_query
);
30 q
.verb
= cpu_to_be16(VSV_SEND_VERSION_NUMBER
);
31 hvsi_send_packet(pv
, &q
.hdr
);
34 static int hvsi_send_close(struct hvsi_priv
*pv
)
36 struct hvsi_control ctrl
;
40 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
;
41 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
42 ctrl
.verb
= cpu_to_be16(VSV_CLOSE_PROTOCOL
);
43 return hvsi_send_packet(pv
, &ctrl
.hdr
);
46 static void hvsi_cd_change(struct hvsi_priv
*pv
, int cd
)
49 pv
->mctrl
|= TIOCM_CD
;
51 pv
->mctrl
&= ~TIOCM_CD
;
53 /* We copy the existing hvsi driver semantics
54 * here which are to trigger a hangup when
55 * we get a carrier loss.
56 * Closing our connection to the server will
59 if (!pv
->is_console
&& pv
->opened
) {
60 pr_devel("HVSI@%x Carrier lost, hanging up !\n",
67 static void hvsi_got_control(struct hvsi_priv
*pv
)
69 struct hvsi_control
*pkt
= (struct hvsi_control
*)pv
->inbuf
;
71 switch (be16_to_cpu(pkt
->verb
)) {
72 case VSV_CLOSE_PROTOCOL
:
73 /* We restart the handshaking */
74 hvsi_start_handshake(pv
);
76 case VSV_MODEM_CTL_UPDATE
:
77 /* Transition of carrier detect */
78 hvsi_cd_change(pv
, be32_to_cpu(pkt
->word
) & HVSI_TSCD
);
83 static void hvsi_got_query(struct hvsi_priv
*pv
)
85 struct hvsi_query
*pkt
= (struct hvsi_query
*)pv
->inbuf
;
86 struct hvsi_query_response r
;
88 /* We only handle version queries */
89 if (be16_to_cpu(pkt
->verb
) != VSV_SEND_VERSION_NUMBER
)
92 pr_devel("HVSI@%x: Got version query, sending response...\n",
95 /* Send version response */
96 r
.hdr
.type
= VS_QUERY_RESPONSE_PACKET_HEADER
;
97 r
.hdr
.len
= sizeof(struct hvsi_query_response
);
98 r
.verb
= cpu_to_be16(VSV_SEND_VERSION_NUMBER
);
99 r
.u
.version
= HVSI_VERSION
;
100 r
.query_seqno
= pkt
->hdr
.seqno
;
101 hvsi_send_packet(pv
, &r
.hdr
);
103 /* Assume protocol is open now */
107 static void hvsi_got_response(struct hvsi_priv
*pv
)
109 struct hvsi_query_response
*r
=
110 (struct hvsi_query_response
*)pv
->inbuf
;
113 case VSV_SEND_MODEM_CTL_STATUS
:
114 hvsi_cd_change(pv
, be32_to_cpu(r
->u
.mctrl_word
) & HVSI_TSCD
);
115 pv
->mctrl_update
= 1;
120 static int hvsi_check_packet(struct hvsi_priv
*pv
)
124 /* Check header validity. If it's invalid, we ditch
125 * the whole buffer and hope we eventually resync
127 if (pv
->inbuf
[0] < 0xfc) {
128 pv
->inbuf_len
= pv
->inbuf_pktlen
= 0;
134 /* Packet incomplete ? */
135 if (pv
->inbuf_len
< len
)
138 pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
139 pv
->termno
, type
, len
);
141 /* We have a packet, yay ! Handle it */
143 case VS_DATA_PACKET_HEADER
:
144 pv
->inbuf_pktlen
= len
- 4;
147 case VS_CONTROL_PACKET_HEADER
:
148 hvsi_got_control(pv
);
150 case VS_QUERY_PACKET_HEADER
:
153 case VS_QUERY_RESPONSE_PACKET_HEADER
:
154 hvsi_got_response(pv
);
158 /* Swallow packet and retry */
159 pv
->inbuf_len
-= len
;
160 memmove(pv
->inbuf
, &pv
->inbuf
[len
], pv
->inbuf_len
);
164 static int hvsi_get_packet(struct hvsi_priv
*pv
)
166 /* If we have room in the buffer, ask HV for more */
167 if (pv
->inbuf_len
< HVSI_INBUF_SIZE
)
168 pv
->inbuf_len
+= pv
->get_chars(pv
->termno
,
169 &pv
->inbuf
[pv
->inbuf_len
],
170 HVSI_INBUF_SIZE
- pv
->inbuf_len
);
172 * If we have at least 4 bytes in the buffer, check for
173 * a full packet and retry
175 if (pv
->inbuf_len
>= 4)
176 return hvsi_check_packet(pv
);
180 int hvsilib_get_chars(struct hvsi_priv
*pv
, char *buf
, int count
)
182 unsigned int tries
, read
= 0;
187 /* If we aren't open, don't do anything in order to avoid races
188 * with connection establishment. The hvc core will call this
189 * before we have returned from notifier_add(), and we need to
190 * avoid multiple users playing with the receive buffer
195 /* We try twice, once with what data we have and once more
196 * after we try to fetch some more from the hypervisor
198 for (tries
= 1; count
&& tries
< 2; tries
++) {
199 /* Consume existing data packet */
200 if (pv
->inbuf_pktlen
) {
201 unsigned int l
= min(count
, (int)pv
->inbuf_pktlen
);
202 memcpy(&buf
[read
], &pv
->inbuf
[pv
->inbuf_cur
], l
);
204 pv
->inbuf_pktlen
-= l
;
211 /* Data packet fully consumed, move down remaning data */
213 pv
->inbuf_len
-= pv
->inbuf_cur
;
214 memmove(pv
->inbuf
, &pv
->inbuf
[pv
->inbuf_cur
],
219 /* Try to get another packet */
220 if (hvsi_get_packet(pv
))
223 if (!pv
->established
) {
224 pr_devel("HVSI@%x: returning -EPIPE\n", pv
->termno
);
230 int hvsilib_put_chars(struct hvsi_priv
*pv
, const char *buf
, int count
)
233 int rc
, adjcount
= min(count
, HVSI_MAX_OUTGOING_DATA
);
238 dp
.hdr
.type
= VS_DATA_PACKET_HEADER
;
239 dp
.hdr
.len
= adjcount
+ sizeof(struct hvsi_header
);
240 memcpy(dp
.data
, buf
, adjcount
);
241 rc
= hvsi_send_packet(pv
, &dp
.hdr
);
247 static void maybe_msleep(unsigned long ms
)
249 /* During early boot, IRQs are disabled, use mdelay */
256 int hvsilib_read_mctrl(struct hvsi_priv
*pv
)
261 pr_devel("HVSI@%x: Querying modem control status...\n",
264 pv
->mctrl_update
= 0;
265 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
266 q
.hdr
.len
= sizeof(struct hvsi_query
);
267 q
.verb
= cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS
);
268 rc
= hvsi_send_packet(pv
, &q
.hdr
);
270 pr_devel("HVSI@%x: Error %d...\n", pv
->termno
, rc
);
274 /* Try for up to 200ms */
275 for (timeout
= 0; timeout
< 20; timeout
++) {
276 if (!pv
->established
)
278 if (pv
->mctrl_update
)
280 if (!hvsi_get_packet(pv
))
286 int hvsilib_write_mctrl(struct hvsi_priv
*pv
, int dtr
)
288 struct hvsi_control ctrl
;
289 unsigned short mctrl
;
296 if (mctrl
== pv
->mctrl
)
300 pr_devel("HVSI@%x: %s DTR...\n", pv
->termno
,
301 dtr
? "Setting" : "Clearing");
303 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
,
304 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
305 ctrl
.verb
= cpu_to_be16(VSV_SET_MODEM_CTL
);
306 ctrl
.mask
= cpu_to_be32(HVSI_TSDTR
);
307 ctrl
.word
= cpu_to_be32(dtr
? HVSI_TSDTR
: 0);
308 return hvsi_send_packet(pv
, &ctrl
.hdr
);
311 void hvsilib_establish(struct hvsi_priv
*pv
)
315 pr_devel("HVSI@%x: Establishing...\n", pv
->termno
);
317 /* Try for up to 200ms, there can be a packet to
318 * start the process waiting for us...
320 for (timeout
= 0; timeout
< 20; timeout
++) {
323 if (!hvsi_get_packet(pv
))
327 /* Failed, send a close connection packet just
330 pr_devel("HVSI@%x: ... sending close\n", pv
->termno
);
334 /* Then restart handshake */
336 pr_devel("HVSI@%x: ... restarting handshake\n", pv
->termno
);
338 hvsi_start_handshake(pv
);
340 pr_devel("HVSI@%x: ... waiting handshake\n", pv
->termno
);
342 /* Try for up to 400ms */
343 for (timeout
= 0; timeout
< 40; timeout
++) {
346 if (!hvsi_get_packet(pv
))
350 if (!pv
->established
) {
351 pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
356 /* Query modem control lines */
358 pr_devel("HVSI@%x: ... established, reading mctrl\n", pv
->termno
);
360 hvsilib_read_mctrl(pv
);
362 /* Set our own DTR */
364 pr_devel("HVSI@%x: ... setting mctrl\n", pv
->termno
);
366 hvsilib_write_mctrl(pv
, 1);
368 /* Set the opened flag so reads are allowed */
373 int hvsilib_open(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
375 pr_devel("HVSI@%x: open !\n", pv
->termno
);
377 /* Keep track of the tty data structure */
378 pv
->tty
= tty_port_tty_get(&hp
->port
);
380 hvsilib_establish(pv
);
385 void hvsilib_close(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
389 pr_devel("HVSI@%x: close !\n", pv
->termno
);
391 if (!pv
->is_console
) {
392 pr_devel("HVSI@%x: Not a console, tearing down\n",
395 /* Clear opened, synchronize with khvcd */
396 spin_lock_irqsave(&hp
->lock
, flags
);
398 spin_unlock_irqrestore(&hp
->lock
, flags
);
400 /* Clear our own DTR */
401 if (!pv
->tty
|| (pv
->tty
->termios
.c_cflag
& HUPCL
))
402 hvsilib_write_mctrl(pv
, 0);
404 /* Tear down the connection */
408 tty_kref_put(pv
->tty
);
412 void hvsilib_init(struct hvsi_priv
*pv
,
413 int (*get_chars
)(uint32_t termno
, char *buf
, int count
),
414 int (*put_chars
)(uint32_t termno
, const char *buf
,
416 int termno
, int is_console
)
418 memset(pv
, 0, sizeof(*pv
));
419 pv
->get_chars
= get_chars
;
420 pv
->put_chars
= put_chars
;
422 pv
->is_console
= is_console
;