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