0001
0002 #include <linux/types.h>
0003 #include <linux/delay.h>
0004 #include <linux/slab.h>
0005 #include <linux/console.h>
0006 #include <asm/hvsi.h>
0007
0008 #include "hvc_console.h"
0009
0010 static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet)
0011 {
0012 packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno));
0013
0014
0015 return pv->put_chars(pv->termno, (char *)packet, packet->len);
0016 }
0017
0018 static void hvsi_start_handshake(struct hvsi_priv *pv)
0019 {
0020 struct hvsi_query q;
0021
0022
0023 pv->established = 0;
0024 atomic_set(&pv->seqno, 0);
0025
0026 pr_devel("HVSI@%x: Handshaking started\n", pv->termno);
0027
0028
0029 q.hdr.type = VS_QUERY_PACKET_HEADER;
0030 q.hdr.len = sizeof(struct hvsi_query);
0031 q.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
0032 hvsi_send_packet(pv, &q.hdr);
0033 }
0034
0035 static int hvsi_send_close(struct hvsi_priv *pv)
0036 {
0037 struct hvsi_control ctrl;
0038
0039 pv->established = 0;
0040
0041 ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;
0042 ctrl.hdr.len = sizeof(struct hvsi_control);
0043 ctrl.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL);
0044 return hvsi_send_packet(pv, &ctrl.hdr);
0045 }
0046
0047 static void hvsi_cd_change(struct hvsi_priv *pv, int cd)
0048 {
0049 if (cd)
0050 pv->mctrl |= TIOCM_CD;
0051 else {
0052 pv->mctrl &= ~TIOCM_CD;
0053
0054
0055
0056
0057
0058
0059
0060 if (!pv->is_console && pv->opened) {
0061 pr_devel("HVSI@%x Carrier lost, hanging up !\n",
0062 pv->termno);
0063 hvsi_send_close(pv);
0064 }
0065 }
0066 }
0067
0068 static void hvsi_got_control(struct hvsi_priv *pv)
0069 {
0070 struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf;
0071
0072 switch (be16_to_cpu(pkt->verb)) {
0073 case VSV_CLOSE_PROTOCOL:
0074
0075 hvsi_start_handshake(pv);
0076 break;
0077 case VSV_MODEM_CTL_UPDATE:
0078
0079 hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD);
0080 break;
0081 }
0082 }
0083
0084 static void hvsi_got_query(struct hvsi_priv *pv)
0085 {
0086 struct hvsi_query *pkt = (struct hvsi_query *)pv->inbuf;
0087 struct hvsi_query_response r;
0088
0089
0090 if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER)
0091 return;
0092
0093 pr_devel("HVSI@%x: Got version query, sending response...\n",
0094 pv->termno);
0095
0096
0097 r.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER;
0098 r.hdr.len = sizeof(struct hvsi_query_response);
0099 r.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
0100 r.u.version = HVSI_VERSION;
0101 r.query_seqno = pkt->hdr.seqno;
0102 hvsi_send_packet(pv, &r.hdr);
0103
0104
0105 pv->established = 1;
0106 }
0107
0108 static void hvsi_got_response(struct hvsi_priv *pv)
0109 {
0110 struct hvsi_query_response *r =
0111 (struct hvsi_query_response *)pv->inbuf;
0112
0113 switch(r->verb) {
0114 case VSV_SEND_MODEM_CTL_STATUS:
0115 hvsi_cd_change(pv, be32_to_cpu(r->u.mctrl_word) & HVSI_TSCD);
0116 pv->mctrl_update = 1;
0117 break;
0118 }
0119 }
0120
0121 static int hvsi_check_packet(struct hvsi_priv *pv)
0122 {
0123 u8 len, type;
0124
0125
0126
0127
0128 if (pv->inbuf[0] < 0xfc) {
0129 pv->inbuf_len = pv->inbuf_pktlen = 0;
0130 return 0;
0131 }
0132 type = pv->inbuf[0];
0133 len = pv->inbuf[1];
0134
0135
0136 if (pv->inbuf_len < len)
0137 return 0;
0138
0139 pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
0140 pv->termno, type, len);
0141
0142
0143 switch(type) {
0144 case VS_DATA_PACKET_HEADER:
0145 pv->inbuf_pktlen = len - 4;
0146 pv->inbuf_cur = 4;
0147 return 1;
0148 case VS_CONTROL_PACKET_HEADER:
0149 hvsi_got_control(pv);
0150 break;
0151 case VS_QUERY_PACKET_HEADER:
0152 hvsi_got_query(pv);
0153 break;
0154 case VS_QUERY_RESPONSE_PACKET_HEADER:
0155 hvsi_got_response(pv);
0156 break;
0157 }
0158
0159
0160 pv->inbuf_len -= len;
0161 memmove(pv->inbuf, &pv->inbuf[len], pv->inbuf_len);
0162 return 1;
0163 }
0164
0165 static int hvsi_get_packet(struct hvsi_priv *pv)
0166 {
0167
0168 if (pv->inbuf_len < HVSI_INBUF_SIZE)
0169 pv->inbuf_len += pv->get_chars(pv->termno,
0170 &pv->inbuf[pv->inbuf_len],
0171 HVSI_INBUF_SIZE - pv->inbuf_len);
0172
0173
0174
0175
0176 if (pv->inbuf_len >= 4)
0177 return hvsi_check_packet(pv);
0178 return 0;
0179 }
0180
0181 int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
0182 {
0183 unsigned int tries, read = 0;
0184
0185 if (WARN_ON(!pv))
0186 return -ENXIO;
0187
0188
0189
0190
0191
0192
0193 if (!pv->opened)
0194 return 0;
0195
0196
0197
0198
0199 for (tries = 1; count && tries < 2; tries++) {
0200
0201 if (pv->inbuf_pktlen) {
0202 unsigned int l = min(count, (int)pv->inbuf_pktlen);
0203 memcpy(&buf[read], &pv->inbuf[pv->inbuf_cur], l);
0204 pv->inbuf_cur += l;
0205 pv->inbuf_pktlen -= l;
0206 count -= l;
0207 read += l;
0208 }
0209 if (count == 0)
0210 break;
0211
0212
0213 if (pv->inbuf_cur) {
0214 pv->inbuf_len -= pv->inbuf_cur;
0215 memmove(pv->inbuf, &pv->inbuf[pv->inbuf_cur],
0216 pv->inbuf_len);
0217 pv->inbuf_cur = 0;
0218 }
0219
0220
0221 if (hvsi_get_packet(pv))
0222 tries--;
0223 }
0224 if (!pv->established) {
0225 pr_devel("HVSI@%x: returning -EPIPE\n", pv->termno);
0226 return -EPIPE;
0227 }
0228 return read;
0229 }
0230
0231 int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count)
0232 {
0233 struct hvsi_data dp;
0234 int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA);
0235
0236 if (WARN_ON(!pv))
0237 return -ENODEV;
0238
0239 dp.hdr.type = VS_DATA_PACKET_HEADER;
0240 dp.hdr.len = adjcount + sizeof(struct hvsi_header);
0241 memcpy(dp.data, buf, adjcount);
0242 rc = hvsi_send_packet(pv, &dp.hdr);
0243 if (rc <= 0)
0244 return rc;
0245 return adjcount;
0246 }
0247
0248 static void maybe_msleep(unsigned long ms)
0249 {
0250
0251 if (irqs_disabled())
0252 mdelay(ms);
0253 else
0254 msleep(ms);
0255 }
0256
0257 int hvsilib_read_mctrl(struct hvsi_priv *pv)
0258 {
0259 struct hvsi_query q;
0260 int rc, timeout;
0261
0262 pr_devel("HVSI@%x: Querying modem control status...\n",
0263 pv->termno);
0264
0265 pv->mctrl_update = 0;
0266 q.hdr.type = VS_QUERY_PACKET_HEADER;
0267 q.hdr.len = sizeof(struct hvsi_query);
0268 q.verb = cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS);
0269 rc = hvsi_send_packet(pv, &q.hdr);
0270 if (rc <= 0) {
0271 pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc);
0272 return rc;
0273 }
0274
0275
0276 for (timeout = 0; timeout < 20; timeout++) {
0277 if (!pv->established)
0278 return -ENXIO;
0279 if (pv->mctrl_update)
0280 return 0;
0281 if (!hvsi_get_packet(pv))
0282 maybe_msleep(10);
0283 }
0284 return -EIO;
0285 }
0286
0287 int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)
0288 {
0289 struct hvsi_control ctrl;
0290 unsigned short mctrl;
0291
0292 mctrl = pv->mctrl;
0293 if (dtr)
0294 mctrl |= TIOCM_DTR;
0295 else
0296 mctrl &= ~TIOCM_DTR;
0297 if (mctrl == pv->mctrl)
0298 return 0;
0299 pv->mctrl = mctrl;
0300
0301 pr_devel("HVSI@%x: %s DTR...\n", pv->termno,
0302 dtr ? "Setting" : "Clearing");
0303
0304 ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,
0305 ctrl.hdr.len = sizeof(struct hvsi_control);
0306 ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL);
0307 ctrl.mask = cpu_to_be32(HVSI_TSDTR);
0308 ctrl.word = cpu_to_be32(dtr ? HVSI_TSDTR : 0);
0309 return hvsi_send_packet(pv, &ctrl.hdr);
0310 }
0311
0312 void hvsilib_establish(struct hvsi_priv *pv)
0313 {
0314 int timeout;
0315
0316 pr_devel("HVSI@%x: Establishing...\n", pv->termno);
0317
0318
0319
0320
0321 for (timeout = 0; timeout < 20; timeout++) {
0322 if (pv->established)
0323 goto established;
0324 if (!hvsi_get_packet(pv))
0325 maybe_msleep(10);
0326 }
0327
0328
0329
0330
0331 pr_devel("HVSI@%x: ... sending close\n", pv->termno);
0332
0333 hvsi_send_close(pv);
0334
0335
0336
0337 pr_devel("HVSI@%x: ... restarting handshake\n", pv->termno);
0338
0339 hvsi_start_handshake(pv);
0340
0341 pr_devel("HVSI@%x: ... waiting handshake\n", pv->termno);
0342
0343
0344 for (timeout = 0; timeout < 40; timeout++) {
0345 if (pv->established)
0346 goto established;
0347 if (!hvsi_get_packet(pv))
0348 maybe_msleep(10);
0349 }
0350
0351 if (!pv->established) {
0352 pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
0353 pv->termno);
0354 return;
0355 }
0356 established:
0357
0358
0359 pr_devel("HVSI@%x: ... established, reading mctrl\n", pv->termno);
0360
0361 hvsilib_read_mctrl(pv);
0362
0363
0364
0365 pr_devel("HVSI@%x: ... setting mctrl\n", pv->termno);
0366
0367 hvsilib_write_mctrl(pv, 1);
0368
0369
0370 wmb();
0371 pv->opened = 1;
0372 }
0373
0374 int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
0375 {
0376 pr_devel("HVSI@%x: open !\n", pv->termno);
0377
0378
0379 pv->tty = tty_port_tty_get(&hp->port);
0380
0381 hvsilib_establish(pv);
0382
0383 return 0;
0384 }
0385
0386 void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
0387 {
0388 unsigned long flags;
0389
0390 pr_devel("HVSI@%x: close !\n", pv->termno);
0391
0392 if (!pv->is_console) {
0393 pr_devel("HVSI@%x: Not a console, tearing down\n",
0394 pv->termno);
0395
0396
0397 spin_lock_irqsave(&hp->lock, flags);
0398 pv->opened = 0;
0399 spin_unlock_irqrestore(&hp->lock, flags);
0400
0401
0402 if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
0403 hvsilib_write_mctrl(pv, 0);
0404
0405
0406 hvsi_send_close(pv);
0407 }
0408
0409 tty_kref_put(pv->tty);
0410 pv->tty = NULL;
0411 }
0412
0413 void hvsilib_init(struct hvsi_priv *pv,
0414 int (*get_chars)(uint32_t termno, char *buf, int count),
0415 int (*put_chars)(uint32_t termno, const char *buf,
0416 int count),
0417 int termno, int is_console)
0418 {
0419 memset(pv, 0, sizeof(*pv));
0420 pv->get_chars = get_chars;
0421 pv->put_chars = put_chars;
0422 pv->termno = termno;
0423 pv->is_console = is_console;
0424 }