1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * TCP Console Driver File: dev_tcpconsole.c 5 * 6 * Evil hack: A console driver that uses a TCP socket. 7 * 8 * Author: Mitch Lichtenberg (mpl@broadcom.com) 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47 48#include "lib_types.h" 49#include "lib_malloc.h" 50#include "lib_printf.h" 51#include "cfe_iocb.h" 52#include "cfe_device.h" 53#include "cfe_ioctl.h" 54#include "addrspace.h" 55 56#include "cfe_timer.h" 57 58#include "bsp_config.h" 59 60#if CFG_TCP 61#include "net_ebuf.h" 62#include "net_api.h" 63 64/* 65 * Friendly warning: Don't put printfs in here or enable any 66 * debugging messages in the TCP stack if you're really 67 * going to use this for your console device. You'll end up 68 * with a recursion loop! 69 */ 70 71/* ********************************************************************* 72 * Constants 73 ********************************************************************* */ 74 75#define TCPCONSOLE_DEFAULT_PORT 23 /* telnet */ 76 77/* ********************************************************************* 78 * Forward 79 ********************************************************************* */ 80 81static void tcpconsole_probe(cfe_driver_t *drv, 82 unsigned long probe_a, unsigned long probe_b, 83 void *probe_ptr); 84 85static int tcpconsole_open(cfe_devctx_t *ctx); 86static int tcpconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 87static int tcpconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 88static int tcpconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 89static int tcpconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 90static int tcpconsole_close(cfe_devctx_t *ctx); 91 92const static cfe_devdisp_t tcpconsole_dispatch = { 93 tcpconsole_open, 94 tcpconsole_read, 95 tcpconsole_inpstat, 96 tcpconsole_write, 97 tcpconsole_ioctl, 98 tcpconsole_close, 99 NULL, 100 NULL 101}; 102 103const cfe_driver_t tcpconsole = { 104 "TCP Console", 105 "tcpconsole", 106 CFE_DEV_SERIAL, 107 &tcpconsole_dispatch, 108 tcpconsole_probe 109}; 110 111 112/* ********************************************************************* 113 * tcpconsole structure 114 ********************************************************************* */ 115 116/* 117 * States our connection can be in 118 */ 119 120#define TCPCONSTAT_IDLE 0 121#define TCPCONSTAT_LISTEN 1 122#define TCPCONSTAT_CONNECTED 2 123#define TCPCONSTAT_DISCONNECTED 3 124#define TCPCONSTAT_BROKEN 4 125 126/* 127 * state information 128 */ 129 130typedef struct tcpconsole_s { 131 int tcp_socket; 132 int tcp_status; 133 int tcp_port; 134} tcpconsole_t; 135 136 137static void tcpconsole_probe(cfe_driver_t *drv, 138 unsigned long probe_a, unsigned long probe_b, 139 void *probe_ptr) 140{ 141 tcpconsole_t *softc; 142 char descr[80]; 143 144 softc = (tcpconsole_t *) KMALLOC(sizeof(tcpconsole_t),0); 145 if (softc) { 146 softc->tcp_socket = -1; 147 softc->tcp_status = TCPCONSTAT_IDLE; 148 xsprintf(descr, "%s", drv->drv_description); 149 150 if (probe_a == 0) probe_a = TCPCONSOLE_DEFAULT_PORT; 151 152 softc->tcp_port = (int)probe_a; 153 154 cfe_attach(drv, softc, NULL, descr); 155 } 156} 157 158 159static int tcpconsole_isready(tcpconsole_t *softc,int *rxbytes) 160{ 161 int res; 162 int connstat,rxeof; 163 164 res = tcp_status(softc->tcp_socket,&connstat,rxbytes,&rxeof); 165 166 /* 167 * Return: 168 * -1 if we could not get status 169 * 0 if we are not connected or are connected and at EOF 170 * 1 if we are connected. 171 */ 172 173 if (res < 0) return res; 174 if (connstat != TCPSTATUS_CONNECTED) return 0; 175 if (!rxeof) return 1; 176 177 return 0; 178} 179 180 181static int tcpconsole_process(tcpconsole_t *softc) 182{ 183 int res = 0; 184 185 switch (softc->tcp_status) { 186 case TCPCONSTAT_IDLE: 187 /* Idle, set up listening socket */ 188 res = tcp_socket(); 189 if (res < 0) { 190 softc->tcp_status = TCPCONSTAT_BROKEN; 191 return res; 192 } 193 softc->tcp_socket = res; 194 195 res = tcp_listen(softc->tcp_socket,softc->tcp_port); 196 197 if (res < 0) { 198 tcp_close(softc->tcp_socket); 199 softc->tcp_status = TCPCONSTAT_BROKEN; 200 softc->tcp_socket = -1; 201 return res; 202 } 203 softc->tcp_status = TCPCONSTAT_LISTEN; 204 break; 205 206 case TCPCONSTAT_LISTEN: 207 /* Still waiting for a connection */ 208 res = 0; 209 if (tcpconsole_isready(softc,NULL) > 0) { 210 softc->tcp_status = TCPCONSTAT_CONNECTED; 211 } 212 break; 213 214 case TCPCONSTAT_CONNECTED: 215 res = 0; /* do nothing, we're okay */ 216 break; 217 218 case TCPCONSTAT_DISCONNECTED: 219 /* Currently connected, kill off this connection */ 220 tcp_close(softc->tcp_socket); 221 softc->tcp_socket = -1; 222 softc->tcp_status = TCPCONSTAT_IDLE; 223 break; 224 225 case TCPCONSTAT_BROKEN: 226 /* Broken. Stay broken. */ 227 res = 0; 228 break; 229 } 230 231 return res; 232} 233 234 235static int tcpconsole_open(cfe_devctx_t *ctx) 236{ 237 return 0; 238} 239 240static int tcpconsole_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 241{ 242 tcpconsole_t *softc = ctx->dev_softc; 243 unsigned char *bptr; 244 int blen; 245 int res; 246 247 POLL(); 248 tcpconsole_process(softc); 249 250 buffer->buf_retlen = 0; 251 252 if (softc->tcp_status == TCPCONSTAT_CONNECTED) { 253 bptr = buffer->buf_ptr; 254 blen = buffer->buf_length; 255 256 if (tcpconsole_isready(softc,NULL) <= 0) { 257 softc->tcp_status = TCPCONSTAT_DISCONNECTED; 258 return 0; 259 } 260 261 res = tcp_recv(softc->tcp_socket,bptr,blen); 262 263 if (res > 0) { 264 buffer->buf_retlen = res; 265 } 266 } 267 268 return 0; 269} 270 271static int tcpconsole_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) 272{ 273 tcpconsole_t *softc = ctx->dev_softc; 274 unsigned int rxbytes; 275 276 POLL(); 277 tcpconsole_process(softc); 278 279 inpstat->inp_status = 0; 280 281 if (softc->tcp_status == TCPCONSTAT_CONNECTED) { 282 if (tcpconsole_isready(softc,&rxbytes) <= 0) { 283 softc->tcp_status = TCPCONSTAT_DISCONNECTED; 284 } 285 else { 286 inpstat->inp_status = (rxbytes > 0); 287 } 288 } 289 290 return 0; 291} 292 293static int tcpconsole_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 294{ 295 tcpconsole_t *softc = ctx->dev_softc; 296 unsigned char *bptr; 297 int blen; 298 int res; 299 300 POLL(); 301 tcpconsole_process(softc); 302 303 buffer->buf_retlen = 0; 304 305 if (softc->tcp_status == TCPCONSTAT_CONNECTED) { 306 bptr = buffer->buf_ptr; 307 blen = buffer->buf_length; 308 309 if (tcpconsole_isready(softc,NULL) <= 0) { 310 softc->tcp_status = TCPCONSTAT_DISCONNECTED; 311 return 0; 312 } 313 314 res = tcp_send(softc->tcp_socket,bptr,blen); 315 316 if (res > 0) { 317 buffer->buf_retlen = res; 318 } 319 } 320 321 return 0; 322} 323 324static int tcpconsole_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 325{ 326 return -1; 327} 328 329static int tcpconsole_close(cfe_devctx_t *ctx) 330{ 331 tcpconsole_t *softc = ctx->dev_softc; 332 333 if (softc->tcp_status == TCPCONSTAT_CONNECTED) { 334 softc->tcp_status = TCPCONSTAT_DISCONNECTED; 335 } 336 337 return 0; 338} 339 340 341#endif 342