xref: /haiku/src/add-ons/kernel/debugger/laplinkll/laplinkll.cpp (revision df2b006ef311defa77d7a970bf34be65bf5e844b)
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 
read_status(uint32 port)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 
write_control(uint32 port,uint8 val)57 static inline void write_control(uint32 port, uint8 val)
58 {
59 	sISAModule->write_io_8(port+2, val);
60 }
61 
write_data(uint32 port,uint8 val)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 
ll_send_sof(laplink_state * st)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 
ll_check_sof(laplink_state * st)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 
ll_ack_sof(laplink_state * st)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 
ll_send_eof(laplink_state * st)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 
ll_send_lnibble(laplink_state * st,uint8 v)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 
ll_send_mnibble(laplink_state * st,uint8 v)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 
ll_wait_lnibble(laplink_state * st,uint8 * v)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 
ll_wait_mnibble(laplink_state * st,uint8 * v)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 
ll_send_byte(laplink_state * st,uint8 v)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 
ll_check_byte(laplink_state * st,uint8 * v)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 
ll_wait_byte(laplink_state * st,uint8 * v)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
ll_send_byte_uf(laplink_state * st,uint8 v)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 
ll_get_byte_uf(laplink_state * st,uint8 * v)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 
ll_send_frame(laplink_state * st,const uint8 * buff,size_t * len)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 
ll_check_frame(laplink_state * st,uint8 * buff,size_t * len)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 
ll_wait_frame(laplink_state * st,uint8 * buff,size_t * len)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
debug_init_laplink(void * kernel_settings)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 
debug_write_laplink(int f,const char * buf,int count)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 
debug_read_laplink(void)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
debugger_puts(const char * s,int32 length)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
std_ops(int32 op,...)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