1#include <linux/types.h> 2#include <linux/delay.h> 3#include <linux/slab.h> 4#include <linux/console.h> 5#include <asm/hvsi.h> 6 7#include "hvc_console.h" 8 9static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet) 10{ 11 packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno)); 12 13 /* Assumes that always succeeds, works in practice */ 14 return pv->put_chars(pv->termno, (char *)packet, packet->len); 15} 16 17static void hvsi_start_handshake(struct hvsi_priv *pv) 18{ 19 struct hvsi_query q; 20 21 /* Reset state */ 22 pv->established = 0; 23 atomic_set(&pv->seqno, 0); 24 25 pr_devel("HVSI@%x: Handshaking started\n", pv->termno); 26 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); 32} 33 34static int hvsi_send_close(struct hvsi_priv *pv) 35{ 36 struct hvsi_control ctrl; 37 38 pv->established = 0; 39 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); 44} 45 46static void hvsi_cd_change(struct hvsi_priv *pv, int cd) 47{ 48 if (cd) 49 pv->mctrl |= TIOCM_CD; 50 else { 51 pv->mctrl &= ~TIOCM_CD; 52 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 57 * do just that. 58 */ 59 if (!pv->is_console && pv->opened) { 60 pr_devel("HVSI@%x Carrier lost, hanging up !\n", 61 pv->termno); 62 hvsi_send_close(pv); 63 } 64 } 65} 66 67static void hvsi_got_control(struct hvsi_priv *pv) 68{ 69 struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf; 70 71 switch (be16_to_cpu(pkt->verb)) { 72 case VSV_CLOSE_PROTOCOL: 73 /* We restart the handshaking */ 74 hvsi_start_handshake(pv); 75 break; 76 case VSV_MODEM_CTL_UPDATE: 77 /* Transition of carrier detect */ 78 hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD); 79 break; 80 } 81} 82 83static void hvsi_got_query(struct hvsi_priv *pv) 84{ 85 struct hvsi_query *pkt = (struct hvsi_query *)pv->inbuf; 86 struct hvsi_query_response r; 87 88 /* We only handle version queries */ 89 if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER) 90 return; 91 92 pr_devel("HVSI@%x: Got version query, sending response...\n", 93 pv->termno); 94 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); 102 103 /* Assume protocol is open now */ 104 pv->established = 1; 105} 106 107static void hvsi_got_response(struct hvsi_priv *pv) 108{ 109 struct hvsi_query_response *r = 110 (struct hvsi_query_response *)pv->inbuf; 111 112 switch(r->verb) { 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; 116 break; 117 } 118} 119 120static int hvsi_check_packet(struct hvsi_priv *pv) 121{ 122 u8 len, type; 123 124 /* Check header validity. If it's invalid, we ditch 125 * the whole buffer and hope we eventually resync 126 */ 127 if (pv->inbuf[0] < 0xfc) { 128 pv->inbuf_len = pv->inbuf_pktlen = 0; 129 return 0; 130 } 131 type = pv->inbuf[0]; 132 len = pv->inbuf[1]; 133 134 /* Packet incomplete ? */ 135 if (pv->inbuf_len < len) 136 return 0; 137 138 pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n", 139 pv->termno, type, len); 140 141 /* We have a packet, yay ! Handle it */ 142 switch(type) { 143 case VS_DATA_PACKET_HEADER: 144 pv->inbuf_pktlen = len - 4; 145 pv->inbuf_cur = 4; 146 return 1; 147 case VS_CONTROL_PACKET_HEADER: 148 hvsi_got_control(pv); 149 break; 150 case VS_QUERY_PACKET_HEADER: 151 hvsi_got_query(pv); 152 break; 153 case VS_QUERY_RESPONSE_PACKET_HEADER: 154 hvsi_got_response(pv); 155 break; 156 } 157 158 /* Swallow packet and retry */ 159 pv->inbuf_len -= len; 160 memmove(pv->inbuf, &pv->inbuf[len], pv->inbuf_len); 161 return 1; 162} 163 164static int hvsi_get_packet(struct hvsi_priv *pv) 165{ 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); 171 /* 172 * If we have at least 4 bytes in the buffer, check for 173 * a full packet and retry 174 */ 175 if (pv->inbuf_len >= 4) 176 return hvsi_check_packet(pv); 177 return 0; 178} 179 180int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) 181{ 182 unsigned int tries, read = 0; 183 184 if (WARN_ON(!pv)) 185 return -ENXIO; 186 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 191 */ 192 if (!pv->opened) 193 return 0; 194 195 /* We try twice, once with what data we have and once more 196 * after we try to fetch some more from the hypervisor 197 */ 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); 203 pv->inbuf_cur += l; 204 pv->inbuf_pktlen -= l; 205 count -= l; 206 read += l; 207 } 208 if (count == 0) 209 break; 210 211 /* Data packet fully consumed, move down remaning data */ 212 if (pv->inbuf_cur) { 213 pv->inbuf_len -= pv->inbuf_cur; 214 memmove(pv->inbuf, &pv->inbuf[pv->inbuf_cur], 215 pv->inbuf_len); 216 pv->inbuf_cur = 0; 217 } 218 219 /* Try to get another packet */ 220 if (hvsi_get_packet(pv)) 221 tries--; 222 } 223 if (!pv->established) { 224 pr_devel("HVSI@%x: returning -EPIPE\n", pv->termno); 225 return -EPIPE; 226 } 227 return read; 228} 229 230int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count) 231{ 232 struct hvsi_data dp; 233 int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); 234 235 if (WARN_ON(!pv)) 236 return -ENODEV; 237 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); 242 if (rc <= 0) 243 return rc; 244 return adjcount; 245} 246 247static void maybe_msleep(unsigned long ms) 248{ 249 /* During early boot, IRQs are disabled, use mdelay */ 250 if (irqs_disabled()) 251 mdelay(ms); 252 else 253 msleep(ms); 254} 255 256int hvsilib_read_mctrl(struct hvsi_priv *pv) 257{ 258 struct hvsi_query q; 259 int rc, timeout; 260 261 pr_devel("HVSI@%x: Querying modem control status...\n", 262 pv->termno); 263 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); 269 if (rc <= 0) { 270 pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc); 271 return rc; 272 } 273 274 /* Try for up to 200ms */ 275 for (timeout = 0; timeout < 20; timeout++) { 276 if (!pv->established) 277 return -ENXIO; 278 if (pv->mctrl_update) 279 return 0; 280 if (!hvsi_get_packet(pv)) 281 maybe_msleep(10); 282 } 283 return -EIO; 284} 285 286int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr) 287{ 288 struct hvsi_control ctrl; 289 unsigned short mctrl; 290 291 mctrl = pv->mctrl; 292 if (dtr) 293 mctrl |= TIOCM_DTR; 294 else 295 mctrl &= ~TIOCM_DTR; 296 if (mctrl == pv->mctrl) 297 return 0; 298 pv->mctrl = mctrl; 299 300 pr_devel("HVSI@%x: %s DTR...\n", pv->termno, 301 dtr ? "Setting" : "Clearing"); 302 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); 309} 310 311void hvsilib_establish(struct hvsi_priv *pv) 312{ 313 int timeout; 314 315 pr_devel("HVSI@%x: Establishing...\n", pv->termno); 316 317 /* Try for up to 200ms, there can be a packet to 318 * start the process waiting for us... 319 */ 320 for (timeout = 0; timeout < 20; timeout++) { 321 if (pv->established) 322 goto established; 323 if (!hvsi_get_packet(pv)) 324 maybe_msleep(10); 325 } 326 327 /* Failed, send a close connection packet just 328 * in case 329 */ 330 pr_devel("HVSI@%x: ... sending close\n", pv->termno); 331 332 hvsi_send_close(pv); 333 334 /* Then restart handshake */ 335 336 pr_devel("HVSI@%x: ... restarting handshake\n", pv->termno); 337 338 hvsi_start_handshake(pv); 339 340 pr_devel("HVSI@%x: ... waiting handshake\n", pv->termno); 341 342 /* Try for up to 400ms */ 343 for (timeout = 0; timeout < 40; timeout++) { 344 if (pv->established) 345 goto established; 346 if (!hvsi_get_packet(pv)) 347 maybe_msleep(10); 348 } 349 350 if (!pv->established) { 351 pr_devel("HVSI@%x: Timeout handshaking, giving up !\n", 352 pv->termno); 353 return; 354 } 355 established: 356 /* Query modem control lines */ 357 358 pr_devel("HVSI@%x: ... established, reading mctrl\n", pv->termno); 359 360 hvsilib_read_mctrl(pv); 361 362 /* Set our own DTR */ 363 364 pr_devel("HVSI@%x: ... setting mctrl\n", pv->termno); 365 366 hvsilib_write_mctrl(pv, 1); 367 368 /* Set the opened flag so reads are allowed */ 369 wmb(); 370 pv->opened = 1; 371} 372 373int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp) 374{ 375 pr_devel("HVSI@%x: open !\n", pv->termno); 376 377 /* Keep track of the tty data structure */ 378 pv->tty = tty_port_tty_get(&hp->port); 379 380 hvsilib_establish(pv); 381 382 return 0; 383} 384 385void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) 386{ 387 unsigned long flags; 388 389 pr_devel("HVSI@%x: close !\n", pv->termno); 390 391 if (!pv->is_console) { 392 pr_devel("HVSI@%x: Not a console, tearing down\n", 393 pv->termno); 394 395 /* Clear opened, synchronize with khvcd */ 396 spin_lock_irqsave(&hp->lock, flags); 397 pv->opened = 0; 398 spin_unlock_irqrestore(&hp->lock, flags); 399 400 /* Clear our own DTR */ 401 if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL)) 402 hvsilib_write_mctrl(pv, 0); 403 404 /* Tear down the connection */ 405 hvsi_send_close(pv); 406 } 407 408 tty_kref_put(pv->tty); 409 pv->tty = NULL; 410} 411 412void 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, 415 int count), 416 int termno, int is_console) 417{ 418 memset(pv, 0, sizeof(*pv)); 419 pv->get_chars = get_chars; 420 pv->put_chars = put_chars; 421 pv->termno = termno; 422 pv->is_console = is_console; 423} 424