1 /* 2 * Copyright 2008, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * François Revol, revol@free.fr 7 * 8 * Copyright 2005, François Revol. 9 */ 10 11 /* 12 Description: Implements a tty on top of the parallel port, 13 using PLIP-like byte-by-byte protocol. 14 Low level stuff. 15 */ 16 17 18 #include <Drivers.h> 19 //#include <parallel_driver.h> 20 #include <KernelExport.h> 21 #include <driver_settings.h> 22 #include <OS.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/stat.h> 26 #include <sys/types.h> 27 #include <unistd.h> 28 #include <ISA.h> 29 30 //XXX: move to Jamfile when adding driver 31 #define _BUILDING_kernel 1 32 33 #if _BUILDING_kernel 34 #include <debug.h> 35 #endif 36 37 #include "laplinkll.h" 38 39 enum { 40 st_sync = 0, // syncing... 41 st_lsb, 42 st_msb, 43 st_error 44 }; 45 46 static isa_module_info *sISAModule; 47 48 #pragma mark // raw access 49 50 static inline uint8 read_status(uint32 port) 51 { 52 uint8 val; 53 val = sISAModule->read_io_8(port+1); 54 return val; 55 } 56 57 static inline void write_control(uint32 port, uint8 val) 58 { 59 sISAModule->write_io_8(port+2, val); 60 } 61 62 static inline void write_data(uint32 port, uint8 val) 63 { 64 sISAModule->write_io_8(port, val); 65 } 66 67 #pragma mark // framing 68 69 status_t ll_send_sof(laplink_state *st) 70 { 71 uint8 v; 72 int tries = LPTSOFTRIES; 73 if (st->rstate != st_sync || st->wstate != st_sync) 74 return B_TIMED_OUT; 75 // check for idle bus 76 if ((read_status(st->port) & 0xf8) != 0x80) 77 return B_TIMED_OUT; 78 // raise ACK 79 write_data(st->port, 0x08); 80 do { 81 spin(LPTSPIN); 82 v = read_status(st->port); 83 if (st->rstate != st_sync) 84 return B_TIMED_OUT; 85 if (tries-- == 0) 86 return B_TIMED_OUT; 87 } while (!(v & 0x08)); 88 st->wstate = st_lsb; 89 return B_OK; 90 } 91 92 status_t ll_check_sof(laplink_state *st) 93 { 94 uint8 v; 95 if (st->rstate != st_sync || st->wstate != st_sync) 96 return EINTR; 97 v = read_status(st->port); 98 if ((v & 0xf8) != 0xc0) 99 return EINTR; 100 return B_OK; 101 } 102 103 status_t ll_ack_sof(laplink_state *st) 104 { 105 write_data(st->port, 0x01); // ack the sof 106 st->rstate = st_lsb; 107 return B_OK; 108 } 109 110 status_t ll_send_eof(laplink_state *st) 111 { 112 /* 113 if (st->rstate != st_sync || st->wstate != st_sync) 114 return B_TIMED_OUT; 115 */ 116 st->rstate = st_sync; 117 st->wstate = st_sync; 118 write_data(st->port, 0x00); 119 return B_OK; 120 } 121 122 #pragma mark // nibbles 123 124 status_t ll_send_lnibble(laplink_state *st, uint8 v) 125 { 126 int tries = LPTNIBTRIES; 127 uint8 s; 128 if (st->rstate != st_sync) 129 goto err; 130 if (st->wstate != st_lsb) 131 goto err; 132 write_data(st->port, v & 0x0f); 133 spin(10); 134 write_data(st->port, (v & 0x0f) | 0x10); 135 // wait for ack 136 do { 137 s = read_status(st->port); 138 if (tries-- == 0) 139 goto err; 140 spin(LPTSPIN); 141 } while (s & 0x80); 142 st->wstate = st_msb; 143 return B_OK; 144 err: 145 st->wstate = st_sync; 146 return B_TIMED_OUT; 147 } 148 149 status_t ll_send_mnibble(laplink_state *st, uint8 v) 150 { 151 int tries = LPTNIBTRIES; 152 uint8 s; 153 if (st->rstate != st_sync) 154 goto err; 155 if (st->wstate != st_msb) 156 goto err; 157 write_data(st->port, (v >> 4) | 0x10); 158 spin(10); 159 write_data(st->port, (v >> 4)); 160 // wait for ack 161 do { 162 s = read_status(st->port); 163 if (tries-- == 0) 164 goto err; 165 spin(LPTSPIN); 166 } while (!(s & 0x80)); 167 st->wstate = st_lsb;//st_sync; 168 return B_OK; 169 err: 170 st->wstate = st_sync; 171 return B_TIMED_OUT; 172 } 173 174 status_t ll_wait_lnibble(laplink_state *st, uint8 *v) 175 { 176 int tries = LPTNIBTRIES; 177 uint8 s; 178 // wait for data 179 do { 180 s = read_status(st->port); 181 if (tries-- == 0) 182 goto err; 183 spin(LPTSPIN); 184 } while ((s & 0x80) || (s != read_status(st->port))); 185 // get the nibble 186 *v = (s >> 3) & 0x0f; 187 st->rstate = st_msb; 188 // tell we got that one 189 write_data(st->port, 0x10); 190 return B_OK; 191 err: 192 st->rstate = st_sync; 193 return B_TIMED_OUT; 194 } 195 196 status_t ll_wait_mnibble(laplink_state *st, uint8 *v) 197 { 198 int tries = LPTNIBTRIES; 199 uint8 s; 200 // wait for data 201 do { 202 s = read_status(st->port); 203 if (tries-- == 0) 204 goto err; 205 spin(LPTSPIN); 206 } while (!(s & 0x80) || (s != read_status(st->port))); 207 // get the nibble 208 *v |= (s << (4-3)) & 0xf0; 209 st->rstate = st_sync; 210 // tell we got that one 211 write_data(st->port, 0x00); 212 return B_OK; 213 err: 214 st->rstate = st_sync; 215 return B_TIMED_OUT; 216 } 217 218 #pragma mark // byte mode 219 220 status_t ll_send_byte(laplink_state *st, uint8 v) 221 { 222 status_t err; 223 err = ll_send_sof(st); 224 if (!err) 225 err = ll_send_lnibble(st, v); 226 if (!err) 227 err = ll_send_mnibble(st, v); 228 if (!err) 229 err = ll_send_eof(st); 230 return err; 231 } 232 233 status_t ll_check_byte(laplink_state *st, uint8 *v) 234 { 235 status_t err; 236 *v = 0; 237 err = ll_check_sof(st); 238 if (err) 239 return err; 240 err = ll_ack_sof(st); 241 if (!err) 242 err = ll_wait_lnibble(st, v); 243 if (!err) 244 err = ll_wait_mnibble(st, v); 245 if (!err) 246 err = ll_send_eof(st); 247 return err; 248 } 249 250 status_t ll_wait_byte(laplink_state *st, uint8 *v) 251 { 252 status_t err; 253 do { 254 spin(LPTSPIN); 255 err = ll_check_byte(st, v); 256 } while (err < B_OK);// } while (err == B_TIMED_OUT); 257 return err; 258 } 259 260 #pragma mark // frame mode 261 262 // unframed 263 static inline status_t ll_send_byte_uf(laplink_state *st, uint8 v) 264 { 265 status_t err; 266 err = ll_send_lnibble(st, v); 267 if (!err) 268 err = ll_send_mnibble(st, v); 269 return err; 270 } 271 272 status_t ll_get_byte_uf(laplink_state *st, uint8 *v) 273 { 274 status_t err; 275 *v = 0; 276 err = ll_wait_lnibble(st, v); 277 if (!err) 278 err = ll_wait_mnibble(st, v); 279 return err; 280 } 281 282 status_t ll_send_frame(laplink_state *st, const uint8 *buff, size_t *len) 283 { 284 status_t err; 285 uint16 pktlen = *len; 286 uint8 cksum = 0; 287 *len = 0; 288 err = ll_send_sof(st); 289 if (err) 290 return err; 291 err = ll_send_byte_uf(st, pktlen & 0xff); 292 if (err) 293 goto err; 294 err = ll_send_byte_uf(st, pktlen >> 8); 295 if (err) 296 goto err; 297 for (*len = 0; *len < pktlen; (*len)++) { 298 err = ll_send_byte_uf(st, buff[*len]); 299 if (err) 300 goto err; 301 cksum += buff[*len]; 302 } 303 err = ll_send_byte_uf(st, cksum); 304 if (err) 305 goto err; 306 307 /*err =*/ ll_send_eof(st); 308 err: 309 310 if (err) { // back to idle 311 *len = 0; 312 ll_send_eof(st); 313 } 314 return err; 315 } 316 317 status_t ll_check_frame(laplink_state *st, uint8 *buff, size_t *len) 318 { 319 status_t err; 320 uint16 pktlen = 0; 321 uint16 wanted; 322 uint8 cksum = 0; 323 uint8 byte; 324 int i; 325 err = ll_check_sof(st); 326 if (err) 327 goto err; 328 err = ll_ack_sof(st); 329 if (err) 330 goto err; 331 // pktlen 332 err = ll_get_byte_uf(st, &byte); 333 if (err) 334 goto err; 335 pktlen = byte; 336 err = ll_get_byte_uf(st, &byte); 337 if (err) 338 goto err; 339 pktlen |= byte << 8; 340 cksum = 0; 341 /*if (pktlen > *len) { 342 dprintf("laplink: check_frame: packet truncated from %d to %d\n", pktlen, *len); 343 }*/ 344 wanted = MIN(pktlen, *len); 345 for (*len = 0; (*len < pktlen); (*len)++) { 346 err = ll_get_byte_uf(st, &byte); 347 if (err) 348 goto err; 349 if (*len < wanted) 350 buff[*len] = byte; 351 cksum += byte; 352 } 353 err = ll_get_byte_uf(st, &byte); 354 if (err) 355 goto err; 356 /* 357 if (cksum != byte) { 358 dprintf("laplink: check_frame: wrong cksum\n"); 359 }*/ 360 err: 361 ll_send_eof(st); 362 return err; 363 } 364 365 status_t ll_wait_frame(laplink_state *st, uint8 *buff, size_t *len) 366 { 367 status_t err; 368 do { 369 spin(LPTSPIN); 370 err = ll_check_frame(st, buff, len); 371 } while (err < B_OK);// } while (err == B_TIMED_OUT); 372 return err; 373 } 374 375 #pragma mark // kdebug io handler 376 377 #if _BUILDING_kernel 378 #define BUFFSZ 256 379 380 static laplink_state llst; 381 static char laplink_in_buf[BUFFSZ]; 382 static char *laplink_in_ptr; 383 static size_t laplink_in_avail; 384 static char laplink_out_buf[BUFFSZ]; 385 386 //XXX: cleanup 387 static status_t debug_init_laplink(void *kernel_settings) 388 { 389 (void)kernel_settings; 390 llst.port = LPTBASE; 391 llst.rstate = st_sync; 392 llst.wstate = st_sync; 393 laplink_in_ptr = laplink_in_buf; 394 laplink_in_avail = 0; 395 return B_OK; 396 } 397 398 static int debug_write_laplink(int f, const char *buf, int count) 399 { 400 status_t err; 401 size_t len; 402 int tries; 403 int i, prev = 0; 404 405 // fix up CR LF issues... to a local buffer (which will get truncated) 406 if (count > 1) { 407 for (i = 0; (i < BUFFSZ-1) && count; i++, buf++, count--) { 408 if ((*buf == '\n') && (prev != '\r')) 409 laplink_out_buf[i++] = '\r'; 410 laplink_out_buf[i] = *buf; 411 prev = *buf; 412 } 413 count = i; 414 buf = laplink_out_buf; 415 } 416 417 tries = 5; 418 do { 419 len = count; 420 err = ll_send_frame(&llst, (const uint8 *)buf, &len); 421 } while (err && tries--); 422 if (err) 423 return 0; 424 return len; 425 } 426 427 static int debug_read_laplink(void) 428 { 429 status_t err = B_OK; 430 while (laplink_in_avail < 1) { 431 laplink_in_avail = BUFFSZ; 432 laplink_in_ptr = laplink_in_buf; 433 err = ll_wait_frame(&llst, (uint8 *)laplink_in_buf, &laplink_in_avail); 434 if (err) 435 laplink_in_avail = 0; 436 } 437 laplink_in_avail--; 438 return *laplink_in_ptr++; 439 } 440 441 442 static int 443 debugger_puts(const char *s, int32 length) 444 { 445 return debug_write_laplink(0, s, (int)length); 446 } 447 448 449 static status_t 450 std_ops(int32 op, ...) 451 { 452 void *handle; 453 bool load = true;//false; 454 455 switch (op) { 456 case B_MODULE_INIT: 457 handle = load_driver_settings("kernel"); 458 if (handle) { 459 load = get_driver_boolean_parameter(handle, 460 "laplinkll_debug_output", load, true); 461 unload_driver_settings(handle); 462 } 463 if (load) { 464 if (get_module(B_ISA_MODULE_NAME, (module_info **)&sISAModule) < B_OK) 465 return B_ERROR; 466 debug_init_laplink(NULL); 467 } 468 return load ? B_OK : B_ERROR; 469 case B_MODULE_UNINIT: 470 put_module(B_ISA_MODULE_NAME); 471 return B_OK; 472 } 473 return B_BAD_VALUE; 474 } 475 476 477 static struct debugger_module_info sModuleInfo = { 478 { 479 "debugger/laplinkll/v1", 480 0, 481 &std_ops 482 }, 483 NULL, 484 NULL, 485 debugger_puts, 486 NULL 487 }; 488 489 module_info *modules[] = { 490 (module_info *)&sModuleInfo, 491 NULL 492 }; 493 494 495 #endif 496 497