1b725ae77Skettenis /*
2b725ae77Skettenis * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3b725ae77Skettenis *
4b725ae77Skettenis * This software may be freely used, copied, modified, and distributed
5b725ae77Skettenis * provided that the above copyright notice is preserved in all copies of the
6b725ae77Skettenis * software.
7b725ae77Skettenis */
8b725ae77Skettenis
9b725ae77Skettenis /* -*-C-*-
10b725ae77Skettenis *
11*63addd46Skettenis * $Revision: 1.3 $
12*63addd46Skettenis * $Date: 2004/12/27 14:00:54 $
13b725ae77Skettenis *
14b725ae77Skettenis *
15b725ae77Skettenis * hostchan.c - Semi Synchronous Host side channel interface for Angel.
16b725ae77Skettenis */
17b725ae77Skettenis
18b725ae77Skettenis #include <stdio.h>
19b725ae77Skettenis
20b725ae77Skettenis #ifdef HAVE_SYS_TIME_H
21b725ae77Skettenis # include <sys/time.h>
22b725ae77Skettenis #else
23b725ae77Skettenis # include "winsock.h"
24b725ae77Skettenis # include "time.h"
25b725ae77Skettenis #endif
26b725ae77Skettenis #include "hsys.h"
27b725ae77Skettenis #include "host.h"
28b725ae77Skettenis #include "logging.h"
29b725ae77Skettenis #include "chandefs.h"
30b725ae77Skettenis #include "chanpriv.h"
31b725ae77Skettenis #include "devclnt.h"
32b725ae77Skettenis #include "buffers.h"
33b725ae77Skettenis #include "drivers.h"
34b725ae77Skettenis #include "adperr.h"
35b725ae77Skettenis #include "devsw.h"
36b725ae77Skettenis #include "hostchan.h"
37b725ae77Skettenis
38b725ae77Skettenis #ifndef UNUSED
39b725ae77Skettenis #define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */
40b725ae77Skettenis #endif
41b725ae77Skettenis
42b725ae77Skettenis #define HEARTRATE 5000000
43b725ae77Skettenis
44b725ae77Skettenis /*
45b725ae77Skettenis * list of available drivers, declared in drivers.c
46b725ae77Skettenis */
47b725ae77Skettenis extern DeviceDescr *devices[];
48b725ae77Skettenis
49b725ae77Skettenis static DeviceDescr *deviceToUse = NULL;
50b725ae77Skettenis
51b725ae77Skettenis static struct Channel {
52b725ae77Skettenis ChannelCallback callback;
53b725ae77Skettenis void *callback_state;
54b725ae77Skettenis } channels[CI_NUM_CHANNELS];
55b725ae77Skettenis
56b725ae77Skettenis static unsigned char HomeSeq;
57b725ae77Skettenis static unsigned char OppoSeq;
58b725ae77Skettenis
59b725ae77Skettenis /*
60b725ae77Skettenis * Handler for DC_APPL packets
61b725ae77Skettenis */
62b725ae77Skettenis static DC_Appl_Handler dc_appl_handler = NULL;
63b725ae77Skettenis
64b725ae77Skettenis /*
65b725ae77Skettenis * slots for registered asynchronous processing callback procedures
66b725ae77Skettenis */
67b725ae77Skettenis #define MAX_ASYNC_CALLBACKS 8
68b725ae77Skettenis static unsigned int num_async_callbacks = 0;
69b725ae77Skettenis static Adp_Async_Callback async_callbacks[MAX_ASYNC_CALLBACKS];
70b725ae77Skettenis
71b725ae77Skettenis /*
72b725ae77Skettenis * writeQueueRoot is the queue of write requests pending acknowledgement
73b725ae77Skettenis * writeQueueSend is the queue of pending write requests which will
74b725ae77Skettenis * be a subset of the list writeQueueRoot
75b725ae77Skettenis */
76b725ae77Skettenis static Packet *writeQueueRoot = NULL;
77b725ae77Skettenis static Packet *writeQueueSend = NULL;
78b725ae77Skettenis static Packet *resend_pkt = NULL;
79b725ae77Skettenis static int resending = FALSE;
80b725ae77Skettenis
81b725ae77Skettenis /* heartbeat_enabled is a flag used to indicate whether the heartbeat is
82b725ae77Skettenis * currently turned on, heartbeat_enabled will be false in situations
83b725ae77Skettenis * where even though a heartbeat is being used it is problematical or
84b725ae77Skettenis * dis-advantageous to have it turned on, for instance during the
85b725ae77Skettenis * initial stages of boot up
86b725ae77Skettenis */
87b725ae77Skettenis unsigned int heartbeat_enabled = FALSE;
88b725ae77Skettenis /* heartbeat_configured is set up by the device driver to indicate whether
89b725ae77Skettenis * the heartbeat is being used during this debug session. In contrast to
90b725ae77Skettenis * heartbeat_enabled it must not be changed during a session. The logic for
91b725ae77Skettenis * deciding whether to send a heartbeat is: Is heartbeat_configured for this
92b725ae77Skettenis * session? if and only if it is then if heartbeat[is currently]_enabled and
93b725ae77Skettenis * we are due to send a pulse then send it
94b725ae77Skettenis */
95b725ae77Skettenis unsigned int heartbeat_configured = TRUE;
96b725ae77Skettenis
Adp_initSeq(void)97b725ae77Skettenis void Adp_initSeq( void ) {
98b725ae77Skettenis Packet *tmp_pkt = writeQueueSend;
99b725ae77Skettenis
100b725ae77Skettenis HomeSeq = 0;
101b725ae77Skettenis OppoSeq = 0;
102b725ae77Skettenis if ( writeQueueSend != NULL) {
103b725ae77Skettenis while (writeQueueSend->pk_next !=NULL) {
104b725ae77Skettenis tmp_pkt = writeQueueSend;
105b725ae77Skettenis writeQueueSend = tmp_pkt->pk_next;
106b725ae77Skettenis DevSW_FreePacket(tmp_pkt);
107b725ae77Skettenis }
108b725ae77Skettenis }
109b725ae77Skettenis tmp_pkt = writeQueueRoot;
110b725ae77Skettenis if ( writeQueueRoot == NULL)
111b725ae77Skettenis return;
112b725ae77Skettenis
113b725ae77Skettenis while (writeQueueRoot->pk_next !=NULL) {
114b725ae77Skettenis tmp_pkt = writeQueueRoot;
115b725ae77Skettenis writeQueueRoot = tmp_pkt->pk_next;
116b725ae77Skettenis DevSW_FreePacket(tmp_pkt);
117b725ae77Skettenis }
118b725ae77Skettenis return;
119b725ae77Skettenis }
120b725ae77Skettenis
121b725ae77Skettenis /**********************************************************************/
122b725ae77Skettenis
123b725ae77Skettenis /*
124b725ae77Skettenis * Function: DummyCallback
125b725ae77Skettenis * Purpose: Default callback routine to handle unexpected input
126b725ae77Skettenis * on a channel
127b725ae77Skettenis *
128b725ae77Skettenis * Params:
129b725ae77Skettenis * Input: packet The received packet
130b725ae77Skettenis *
131b725ae77Skettenis * state Contains nothing of significance
132b725ae77Skettenis *
133b725ae77Skettenis * Returns: Nothing
134b725ae77Skettenis */
DummyCallback(Packet * packet,void * state)135b725ae77Skettenis static void DummyCallback(Packet *packet, void *state)
136b725ae77Skettenis {
137b725ae77Skettenis ChannelID chan;
138b725ae77Skettenis const char fmt[] = "Unexpected read on channel %u, length %d\n";
139b725ae77Skettenis char fmtbuf[sizeof(fmt) + 24];
140b725ae77Skettenis
141b725ae77Skettenis UNUSED(state);
142b725ae77Skettenis
143b725ae77Skettenis chan = *(packet->pk_buffer);
144b725ae77Skettenis sprintf(fmtbuf, fmt, chan, packet->pk_length);
145b725ae77Skettenis printf(fmtbuf);
146b725ae77Skettenis
147b725ae77Skettenis /*
148b725ae77Skettenis * junk this packet
149b725ae77Skettenis */
150b725ae77Skettenis DevSW_FreePacket(packet);
151b725ae77Skettenis }
152b725ae77Skettenis
153b725ae77Skettenis /*
154b725ae77Skettenis * Function: BlockingCallback
155b725ae77Skettenis * Purpose: Callback routine used to implement a blocking read call
156b725ae77Skettenis *
157b725ae77Skettenis * Params:
158b725ae77Skettenis * Input: packet The received packet.
159b725ae77Skettenis *
160b725ae77Skettenis * Output: state Address of higher level's pointer to the received
161b725ae77Skettenis * packet.
162b725ae77Skettenis *
163b725ae77Skettenis * Returns: Nothing
164b725ae77Skettenis */
BlockingCallback(Packet * packet,void * state)165b725ae77Skettenis static void BlockingCallback(Packet *packet, void *state)
166b725ae77Skettenis {
167b725ae77Skettenis /*
168b725ae77Skettenis * Pass the packet back to the caller which requested a packet
169b725ae77Skettenis * from this channel. This also flags the completion of the I/O
170b725ae77Skettenis * request to the blocking read call.
171b725ae77Skettenis */
172b725ae77Skettenis *((Packet **)state) = packet;
173b725ae77Skettenis }
174b725ae77Skettenis
175b725ae77Skettenis /*
176b725ae77Skettenis * Function: FireCallback
177b725ae77Skettenis * Purpose: Pass received packet along to the callback routine for
178b725ae77Skettenis * the appropriate channel
179b725ae77Skettenis *
180b725ae77Skettenis * Params:
181b725ae77Skettenis * Input: packet The received packet.
182b725ae77Skettenis *
183b725ae77Skettenis * Returns: Nothing
184b725ae77Skettenis *
185b725ae77Skettenis * Post-conditions: The Target-to-Host sequence number for the channel
186b725ae77Skettenis * will have been incremented.
187b725ae77Skettenis */
FireCallback(Packet * packet)188b725ae77Skettenis static void FireCallback(Packet *packet)
189b725ae77Skettenis {
190b725ae77Skettenis ChannelID chan;
191b725ae77Skettenis struct Channel *ch;
192b725ae77Skettenis
193b725ae77Skettenis /*
194b725ae77Skettenis * is this a sensible channel number?
195b725ae77Skettenis */
196b725ae77Skettenis chan = *(packet->pk_buffer);
197b725ae77Skettenis if (invalidChannelID(chan))
198b725ae77Skettenis {
199b725ae77Skettenis printf("ERROR: invalid ChannelID received from target\n");
200b725ae77Skettenis
201b725ae77Skettenis /*
202b725ae77Skettenis * free the packet's resources, 'cause no-one else will
203b725ae77Skettenis */
204b725ae77Skettenis DevSW_FreePacket(packet);
205b725ae77Skettenis return;
206b725ae77Skettenis }
207b725ae77Skettenis
208b725ae77Skettenis /*
209b725ae77Skettenis * looks OK - increment sequence number, and pass packet to callback
210b725ae77Skettenis */
211b725ae77Skettenis ch = channels + chan;
212b725ae77Skettenis (ch->callback)(packet, ch->callback_state);
213b725ae77Skettenis }
214b725ae77Skettenis
215b725ae77Skettenis /**********************************************************************/
216b725ae77Skettenis
217b725ae77Skettenis /*
218b725ae77Skettenis * These are the externally visible functions. They are documented
219b725ae77Skettenis * in hostchan.h
220b725ae77Skettenis */
Adp_addToQueue(Packet ** head,Packet * newpkt)221b725ae77Skettenis void Adp_addToQueue(Packet **head, Packet *newpkt)
222b725ae77Skettenis {
223b725ae77Skettenis /*
224b725ae77Skettenis * this is a bit of a hack
225b725ae77Skettenis */
226b725ae77Skettenis Packet *pk;
227b725ae77Skettenis
228b725ae77Skettenis /*
229b725ae77Skettenis * make sure that the hack we are about to use will work as expected
230b725ae77Skettenis */
231b725ae77Skettenis ASSERT(&(((Packet *)0)->pk_next) == 0, "bad struct Packet layout");
232b725ae77Skettenis
233b725ae77Skettenis #if defined(DEBUG) && 0
234b725ae77Skettenis printf("Adp_addToQueue(%p, %p)\n", head, newpkt);
235b725ae77Skettenis #endif
236b725ae77Skettenis
237b725ae77Skettenis /*
238b725ae77Skettenis * here's the hack - it relies upon the next
239b725ae77Skettenis * pointer being at the start of Packet.
240b725ae77Skettenis */
241b725ae77Skettenis pk = (Packet *)(head);
242b725ae77Skettenis
243b725ae77Skettenis /*
244b725ae77Skettenis * skip to the end of the queue
245b725ae77Skettenis */
246b725ae77Skettenis while (pk->pk_next != NULL)
247b725ae77Skettenis pk = pk->pk_next;
248b725ae77Skettenis
249b725ae77Skettenis /*
250b725ae77Skettenis * now add the new element
251b725ae77Skettenis */
252b725ae77Skettenis newpkt->pk_next = NULL;
253b725ae77Skettenis pk->pk_next = newpkt;
254b725ae77Skettenis }
255b725ae77Skettenis
Adp_removeFromQueue(Packet ** head)256b725ae77Skettenis Packet *Adp_removeFromQueue(Packet **head)
257b725ae77Skettenis {
258b725ae77Skettenis struct Packet *pk;
259b725ae77Skettenis
260b725ae77Skettenis pk = *head;
261b725ae77Skettenis
262b725ae77Skettenis if (pk != NULL)
263b725ae77Skettenis *head = pk->pk_next;
264b725ae77Skettenis
265b725ae77Skettenis return pk;
266b725ae77Skettenis }
267b725ae77Skettenis
Adp_SetLogEnable(int logEnableFlag)268b725ae77Skettenis void Adp_SetLogEnable(int logEnableFlag)
269b725ae77Skettenis {
270b725ae77Skettenis DevSW_SetLogEnable(logEnableFlag);
271b725ae77Skettenis }
272b725ae77Skettenis
Adp_SetLogfile(const char * filename)273b725ae77Skettenis void Adp_SetLogfile(const char *filename)
274b725ae77Skettenis {
275b725ae77Skettenis DevSW_SetLogfile(filename);
276b725ae77Skettenis }
277b725ae77Skettenis
Adp_OpenDevice(const char * name,const char * arg,unsigned int heartbeat_on)278b725ae77Skettenis AdpErrs Adp_OpenDevice(const char *name, const char *arg,
279b725ae77Skettenis unsigned int heartbeat_on)
280b725ae77Skettenis {
281b725ae77Skettenis int i;
282b725ae77Skettenis AdpErrs retc;
283b725ae77Skettenis ChannelID chan;
284b725ae77Skettenis
285b725ae77Skettenis #ifdef DEBUG
286b725ae77Skettenis printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : "<NULL>");
287b725ae77Skettenis #endif
288b725ae77Skettenis
289b725ae77Skettenis heartbeat_configured = heartbeat_on;
290b725ae77Skettenis if (deviceToUse != NULL)
291b725ae77Skettenis return adp_device_already_open;
292b725ae77Skettenis
293b725ae77Skettenis for (i = 0; (deviceToUse = devices[i]) != NULL; ++i)
294b725ae77Skettenis if (DevSW_Match(deviceToUse, name, arg) == adp_ok)
295b725ae77Skettenis break;
296b725ae77Skettenis
297b725ae77Skettenis if (deviceToUse == NULL)
298b725ae77Skettenis return adp_device_not_found;
299b725ae77Skettenis
300b725ae77Skettenis /*
301b725ae77Skettenis * we seem to have found a suitable device driver, so try to open it
302b725ae77Skettenis */
303b725ae77Skettenis if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok)
304b725ae77Skettenis {
305b725ae77Skettenis /* we don't have a device to use */
306b725ae77Skettenis deviceToUse = NULL;
307b725ae77Skettenis return retc;
308b725ae77Skettenis }
309b725ae77Skettenis
310b725ae77Skettenis /*
311b725ae77Skettenis * there is no explicit open on channels any more, so
312b725ae77Skettenis * initialise state for all channels.
313b725ae77Skettenis */
314b725ae77Skettenis for (chan = 0; chan < CI_NUM_CHANNELS; ++chan)
315b725ae77Skettenis {
316b725ae77Skettenis struct Channel *ch = channels + chan;
317b725ae77Skettenis
318b725ae77Skettenis ch->callback = DummyCallback;
319b725ae77Skettenis ch->callback_state = NULL;
320b725ae77Skettenis OppoSeq = 0;
321b725ae77Skettenis HomeSeq = 0;
322b725ae77Skettenis }
323b725ae77Skettenis
324b725ae77Skettenis return adp_ok;
325b725ae77Skettenis }
326b725ae77Skettenis
Adp_CloseDevice(void)327b725ae77Skettenis AdpErrs Adp_CloseDevice(void)
328b725ae77Skettenis {
329b725ae77Skettenis AdpErrs retc;
330b725ae77Skettenis
331b725ae77Skettenis #ifdef DEBUG
332b725ae77Skettenis printf("Adp_CloseDevice\n");
333b725ae77Skettenis #endif
334b725ae77Skettenis
335b725ae77Skettenis if (deviceToUse == NULL)
336b725ae77Skettenis return adp_device_not_open;
337b725ae77Skettenis
338b725ae77Skettenis heartbeat_enabled = FALSE;
339b725ae77Skettenis
340b725ae77Skettenis retc = DevSW_Close(deviceToUse, DC_DBUG);
341b725ae77Skettenis
342b725ae77Skettenis /*
343b725ae77Skettenis * we have to clear deviceToUse, even when the lower layers
344b725ae77Skettenis * faulted the close, otherwise the condition will never clear
345b725ae77Skettenis */
346b725ae77Skettenis if (retc != adp_ok)
347b725ae77Skettenis WARN("DevSW_Close faulted the call");
348b725ae77Skettenis
349b725ae77Skettenis deviceToUse = NULL;
350b725ae77Skettenis return retc;
351b725ae77Skettenis }
352b725ae77Skettenis
Adp_Ioctl(int opcode,void * args)353b725ae77Skettenis AdpErrs Adp_Ioctl(int opcode, void *args)
354b725ae77Skettenis {
355b725ae77Skettenis #ifdef DEBUG
356b725ae77Skettenis printf("Adp_Ioctl\n");
357b725ae77Skettenis #endif
358b725ae77Skettenis
359b725ae77Skettenis if (deviceToUse == NULL)
360b725ae77Skettenis return adp_device_not_open;
361b725ae77Skettenis
362b725ae77Skettenis return DevSW_Ioctl(deviceToUse, opcode, args);
363b725ae77Skettenis }
364b725ae77Skettenis
Adp_ChannelRegisterRead(const ChannelID chan,const ChannelCallback cbfunc,void * cbstate)365b725ae77Skettenis AdpErrs Adp_ChannelRegisterRead(const ChannelID chan,
366b725ae77Skettenis const ChannelCallback cbfunc,
367b725ae77Skettenis void *cbstate)
368b725ae77Skettenis {
369b725ae77Skettenis #ifdef DEBUG
370b725ae77Skettenis printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate);
371b725ae77Skettenis #endif
372b725ae77Skettenis
373b725ae77Skettenis if (deviceToUse == NULL)
374b725ae77Skettenis return adp_device_not_open;
375b725ae77Skettenis
376b725ae77Skettenis if (invalidChannelID(chan))
377b725ae77Skettenis return adp_bad_channel_id;
378b725ae77Skettenis
379b725ae77Skettenis if (cbfunc == NULL)
380b725ae77Skettenis {
381b725ae77Skettenis channels[chan].callback = DummyCallback;
382b725ae77Skettenis channels[chan].callback_state = NULL;
383b725ae77Skettenis }
384b725ae77Skettenis else
385b725ae77Skettenis {
386b725ae77Skettenis channels[chan].callback = cbfunc;
387b725ae77Skettenis channels[chan].callback_state = cbstate;
388b725ae77Skettenis }
389b725ae77Skettenis
390b725ae77Skettenis return adp_ok;
391b725ae77Skettenis }
392b725ae77Skettenis
Adp_ChannelRead(const ChannelID chan,Packet ** packet)393b725ae77Skettenis AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet)
394b725ae77Skettenis {
395b725ae77Skettenis struct Channel *ch;
396b725ae77Skettenis
397b725ae77Skettenis #ifdef DEBUG
398b725ae77Skettenis printf("Adp_ChannelRead(%d, %x)\n", chan, *packet);
399b725ae77Skettenis #endif
400b725ae77Skettenis
401b725ae77Skettenis if (deviceToUse == NULL)
402b725ae77Skettenis return adp_device_not_open;
403b725ae77Skettenis
404b725ae77Skettenis if (invalidChannelID(chan))
405b725ae77Skettenis return adp_bad_channel_id;
406b725ae77Skettenis
407b725ae77Skettenis /*
408b725ae77Skettenis * if a callback has already been registered for this
409b725ae77Skettenis * channel, then we do not allow this blocking read.
410b725ae77Skettenis */
411b725ae77Skettenis ch = channels + chan;
412b725ae77Skettenis if (ch->callback != DummyCallback)
413b725ae77Skettenis return adp_callback_already_registered;
414b725ae77Skettenis
415b725ae77Skettenis /*
416b725ae77Skettenis * OK, use our own callback to wait for a packet to arrive
417b725ae77Skettenis * on this channel
418b725ae77Skettenis */
419b725ae77Skettenis ch->callback = BlockingCallback;
420b725ae77Skettenis ch->callback_state = packet;
421b725ae77Skettenis *packet = NULL;
422b725ae77Skettenis
423b725ae77Skettenis /*
424b725ae77Skettenis * keep polling until a packet appears for this channel
425b725ae77Skettenis */
426b725ae77Skettenis while (((volatile Packet *)(*packet)) == NULL)
427b725ae77Skettenis /*
428b725ae77Skettenis * this call will block until a packet is read on any channel
429b725ae77Skettenis */
430b725ae77Skettenis Adp_AsynchronousProcessing(async_block_on_read);
431b725ae77Skettenis
432b725ae77Skettenis /*
433b725ae77Skettenis * OK, the packet has arrived: clear the callback
434b725ae77Skettenis */
435b725ae77Skettenis ch->callback = DummyCallback;
436b725ae77Skettenis ch->callback_state = NULL;
437b725ae77Skettenis
438b725ae77Skettenis return adp_ok;
439b725ae77Skettenis }
440b725ae77Skettenis
ChannelWrite(const ChannelID chan,Packet * packet,AsyncMode mode)441b725ae77Skettenis static AdpErrs ChannelWrite(
442b725ae77Skettenis const ChannelID chan, Packet *packet, AsyncMode mode)
443b725ae77Skettenis {
444b725ae77Skettenis struct Channel *ch;
445b725ae77Skettenis unsigned char *cptr;
446b725ae77Skettenis
447b725ae77Skettenis #ifdef DEBUG
448b725ae77Skettenis printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet );
449b725ae77Skettenis #endif
450b725ae77Skettenis
451b725ae77Skettenis if (deviceToUse == NULL)
452b725ae77Skettenis return adp_device_not_open;
453b725ae77Skettenis
454b725ae77Skettenis if (invalidChannelID(chan))
455b725ae77Skettenis return adp_bad_channel_id;
456b725ae77Skettenis
457b725ae77Skettenis /*
458b725ae77Skettenis * fill in the channels header at the start of this buffer
459b725ae77Skettenis */
460b725ae77Skettenis ch = channels + chan;
461b725ae77Skettenis cptr = packet->pk_buffer;
462b725ae77Skettenis *cptr++ = chan;
463b725ae77Skettenis *cptr = 0;
464b725ae77Skettenis packet->pk_length += CHAN_HEADER_SIZE;
465b725ae77Skettenis
466b725ae77Skettenis /*
467b725ae77Skettenis * OK, add this packet to the write queue, and try to flush it out
468b725ae77Skettenis */
469b725ae77Skettenis
470b725ae77Skettenis Adp_addToQueue(&writeQueueSend, packet);
471b725ae77Skettenis Adp_AsynchronousProcessing(mode);
472b725ae77Skettenis
473b725ae77Skettenis return adp_ok;
474b725ae77Skettenis }
475b725ae77Skettenis
Adp_ChannelWrite(const ChannelID chan,Packet * packet)476b725ae77Skettenis AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
477b725ae77Skettenis return ChannelWrite(chan, packet, async_block_on_write);
478b725ae77Skettenis }
479b725ae77Skettenis
Adp_ChannelWriteAsync(const ChannelID chan,Packet * packet)480b725ae77Skettenis AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
481b725ae77Skettenis return ChannelWrite(chan, packet, async_block_on_nothing);
482b725ae77Skettenis }
483b725ae77Skettenis
send_resend_msg(DeviceID devid)484b725ae77Skettenis static AdpErrs send_resend_msg(DeviceID devid) {
485b725ae77Skettenis
486b725ae77Skettenis /*
487b725ae77Skettenis * Send a resend message, usually in response to a bad packet or
488b725ae77Skettenis * a resend request */
489b725ae77Skettenis Packet * packet;
490b725ae77Skettenis packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
491b725ae77Skettenis packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
492b725ae77Skettenis packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
493b725ae77Skettenis packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
494b725ae77Skettenis packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND;
495b725ae77Skettenis packet->pk_length = CF_DATA_BYTE_POS;
496b725ae77Skettenis return DevSW_Write(deviceToUse, packet, devid);
497b725ae77Skettenis }
498b725ae77Skettenis
check_seq(unsigned char msg_home,unsigned char msg_oppo)499b725ae77Skettenis static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) {
500b725ae77Skettenis Packet *tmp_pkt;
501b725ae77Skettenis
502b725ae77Skettenis UNUSED(msg_oppo);
503b725ae77Skettenis /*
504b725ae77Skettenis * check if we have got an ack for anything and if so remove it from the
505b725ae77Skettenis * queue
506b725ae77Skettenis */
507b725ae77Skettenis if (msg_home == (unsigned char)(OppoSeq+1)) {
508b725ae77Skettenis /*
509b725ae77Skettenis * arrived in sequence can increment our opposing seq number and remove
510b725ae77Skettenis * the relevant packet from our queue
511b725ae77Skettenis * check that the packet we're going to remove really is the right one
512b725ae77Skettenis */
513b725ae77Skettenis tmp_pkt = writeQueueRoot;
514b725ae77Skettenis while ((tmp_pkt->pk_next != NULL) &&
515b725ae77Skettenis (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS]
516b725ae77Skettenis != OppoSeq)){
517b725ae77Skettenis tmp_pkt = tmp_pkt->pk_next;
518b725ae77Skettenis }
519b725ae77Skettenis OppoSeq++;
520b725ae77Skettenis if (tmp_pkt->pk_next == NULL) {
521b725ae77Skettenis #ifdef DEBUG
522b725ae77Skettenis printf("trying to remove a non existant packet\n");
523b725ae77Skettenis #endif
524b725ae77Skettenis return adp_bad_packet;
525b725ae77Skettenis }
526b725ae77Skettenis else {
527b725ae77Skettenis Packet *tmp = tmp_pkt->pk_next;
528b725ae77Skettenis #ifdef RET_DEBUG
529b725ae77Skettenis printf("removing a packet from the root queue\n");
530b725ae77Skettenis #endif
531b725ae77Skettenis tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next;
532b725ae77Skettenis /* remove the appropriate packet */
533b725ae77Skettenis DevSW_FreePacket(tmp);
534b725ae77Skettenis return adp_ok;
535b725ae77Skettenis }
536b725ae77Skettenis }
537b725ae77Skettenis else if (msg_home < (unsigned char) (OppoSeq+1)){
538b725ae77Skettenis /* already received this message */
539b725ae77Skettenis #ifdef RET_DEBUG
540b725ae77Skettenis printf("sequence numbers low\n");
541b725ae77Skettenis #endif
542b725ae77Skettenis return adp_seq_low;
543b725ae77Skettenis }
544b725ae77Skettenis else { /* we've missed something */
545b725ae77Skettenis #ifdef RET_DEBUG
546b725ae77Skettenis printf("sequence numbers high\n");
547b725ae77Skettenis #endif
548b725ae77Skettenis return adp_seq_high;
549b725ae77Skettenis }
550b725ae77Skettenis }
551b725ae77Skettenis
tv_diff(const struct timeval * time_now,const struct timeval * time_was)552b725ae77Skettenis static unsigned long tv_diff(const struct timeval *time_now,
553b725ae77Skettenis const struct timeval *time_was)
554b725ae77Skettenis {
555b725ae77Skettenis return ( ((time_now->tv_sec * 1000000) + time_now->tv_usec)
556b725ae77Skettenis - ((time_was->tv_sec * 1000000) + time_was->tv_usec) );
557b725ae77Skettenis }
558b725ae77Skettenis
559b725ae77Skettenis #if !defined(__unix) && !defined(__CYGWIN__)
gettimeofday(struct timeval * time_now,void * dummy)560b725ae77Skettenis static void gettimeofday( struct timeval *time_now, void *dummy )
561b725ae77Skettenis {
562b725ae77Skettenis time_t t = clock();
563b725ae77Skettenis UNUSED(dummy);
564b725ae77Skettenis time_now->tv_sec = t/CLOCKS_PER_SEC;
565b725ae77Skettenis time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC);
566b725ae77Skettenis }
567b725ae77Skettenis #endif
568b725ae77Skettenis
pacemaker(void)569b725ae77Skettenis static AdpErrs pacemaker(void)
570b725ae77Skettenis {
571b725ae77Skettenis Packet *packet;
572b725ae77Skettenis
573b725ae77Skettenis packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
574b725ae77Skettenis if (packet == NULL) {
575b725ae77Skettenis printf("ERROR: could not allocate a packet in pacemaker()\n");
576b725ae77Skettenis return adp_malloc_failure;
577b725ae77Skettenis }
578b725ae77Skettenis packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
579b725ae77Skettenis packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
580b725ae77Skettenis packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
581b725ae77Skettenis packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT;
582b725ae77Skettenis packet->pk_length = CF_DATA_BYTE_POS;
583b725ae77Skettenis return DevSW_Write(deviceToUse, packet, DC_DBUG);
584b725ae77Skettenis }
585b725ae77Skettenis
586b725ae77Skettenis #ifdef FAKE_BAD_LINE_RX
fake_bad_line_rx(const Packet * const packet,AdpErrs adp_err)587b725ae77Skettenis static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err )
588b725ae77Skettenis {
589b725ae77Skettenis static unsigned int bl_num = 0;
590b725ae77Skettenis
591b725ae77Skettenis if ( (packet != NULL)
592b725ae77Skettenis && (bl_num++ >= 20 )
593b725ae77Skettenis && ((bl_num % FAKE_BAD_LINE_RX) == 0))
594b725ae77Skettenis {
595b725ae77Skettenis printf("DEBUG: faking a bad packet\n");
596b725ae77Skettenis return adp_bad_packet;
597b725ae77Skettenis }
598b725ae77Skettenis return adp_err;
599b725ae77Skettenis }
600b725ae77Skettenis #endif /* def FAKE_BAD_LINE_RX */
601b725ae77Skettenis
602b725ae77Skettenis #ifdef FAKE_BAD_LINE_TX
603b725ae77Skettenis static unsigned char tmp_ch;
604b725ae77Skettenis
fake_bad_line_tx(void)605b725ae77Skettenis static void fake_bad_line_tx( void )
606b725ae77Skettenis {
607b725ae77Skettenis static unsigned int bl_num = 0;
608b725ae77Skettenis
609b725ae77Skettenis /* give the thing a chance to boot then try corrupting stuff */
610b725ae77Skettenis if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0))
611b725ae77Skettenis {
612b725ae77Skettenis printf("DEBUG: faking a bad packet for tx\n");
613b725ae77Skettenis tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS];
614b725ae77Skettenis writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77;
615b725ae77Skettenis }
616b725ae77Skettenis }
617b725ae77Skettenis
unfake_bad_line_tx(void)618b725ae77Skettenis static void unfake_bad_line_tx( void )
619b725ae77Skettenis {
620b725ae77Skettenis static unsigned int bl_num = 0;
621b725ae77Skettenis
622b725ae77Skettenis /*
623b725ae77Skettenis * must reset the packet so that its not corrupted when we
624b725ae77Skettenis * resend it
625b725ae77Skettenis */
626b725ae77Skettenis if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0))
627b725ae77Skettenis {
628b725ae77Skettenis writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch;
629b725ae77Skettenis }
630b725ae77Skettenis }
631b725ae77Skettenis #endif /* def FAKE_BAD_LINE_TX */
632b725ae77Skettenis
633b725ae77Skettenis /*
634b725ae77Skettenis * NOTE: we are assuming that a resolution of microseconds will
635b725ae77Skettenis * be good enough for the purporses of the heartbeat. If this proves
636b725ae77Skettenis * not to be the case then we may need a rethink, possibly using
637b725ae77Skettenis * [get,set]itimer
638b725ae77Skettenis */
639b725ae77Skettenis static struct timeval time_now;
640b725ae77Skettenis static struct timeval time_lastalive;
641b725ae77Skettenis
async_process_dbug_read(const AsyncMode mode,bool * const finished)642b725ae77Skettenis static void async_process_dbug_read( const AsyncMode mode,
643b725ae77Skettenis bool *const finished )
644b725ae77Skettenis {
645b725ae77Skettenis Packet *packet;
646b725ae77Skettenis unsigned int msg_home, msg_oppo;
647b725ae77Skettenis AdpErrs adp_err;
648b725ae77Skettenis
649b725ae77Skettenis adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet,
650b725ae77Skettenis mode == async_block_on_read );
651b725ae77Skettenis
652b725ae77Skettenis #ifdef FAKE_BAD_LINE_RX
653b725ae77Skettenis adp_err = fake_bad_line_rx( packet, adp_err );
654b725ae77Skettenis #endif
655b725ae77Skettenis
656b725ae77Skettenis if (adp_err == adp_bad_packet) {
657b725ae77Skettenis /* We got a bad packet, ask for a resend, send a resend message */
658b725ae77Skettenis #ifdef DEBUG
659b725ae77Skettenis printf("received a bad packet\n");
660b725ae77Skettenis #endif
661b725ae77Skettenis send_resend_msg(DC_DBUG);
662b725ae77Skettenis }
663b725ae77Skettenis else if (packet != NULL)
664b725ae77Skettenis {
665b725ae77Skettenis /* update the heartbeat clock */
666b725ae77Skettenis gettimeofday(&time_lastalive, NULL);
667b725ae77Skettenis
668b725ae77Skettenis /*
669b725ae77Skettenis * we got a live one here - were we waiting for it?
670b725ae77Skettenis */
671b725ae77Skettenis if (mode == async_block_on_read)
672b725ae77Skettenis /* not any more */
673b725ae77Skettenis *finished = TRUE;
674b725ae77Skettenis #ifdef RETRANS
675b725ae77Skettenis
676b725ae77Skettenis if (packet->pk_length < CF_DATA_BYTE_POS) {
677b725ae77Skettenis /* we've got a packet with no header information! */
678b725ae77Skettenis printf("ERROR: packet with no transport header\n");
679b725ae77Skettenis send_resend_msg(DC_DBUG);
680b725ae77Skettenis }
681b725ae77Skettenis else {
682b725ae77Skettenis #ifdef RET_DEBUG
683b725ae77Skettenis unsigned int c;
684b725ae77Skettenis #endif
685b725ae77Skettenis /*
686b725ae77Skettenis * TODO: Check to see if its acknowledgeing anything, remove
687b725ae77Skettenis * those packets it is from the queue. If its a retrans add the
688b725ae77Skettenis * packets to the queue
689b725ae77Skettenis */
690b725ae77Skettenis msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS];
691b725ae77Skettenis msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS];
692b725ae77Skettenis #ifdef RET_DEBUG
693b725ae77Skettenis printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
694b725ae77Skettenis msg_home, msg_oppo);
695b725ae77Skettenis for (c=0;c<packet->pk_length;c++)
696b725ae77Skettenis printf("%02.2x", packet->pk_buffer[c]);
697b725ae77Skettenis printf("\n");
698b725ae77Skettenis #endif
699b725ae77Skettenis /* now was it a resend request? */
700b725ae77Skettenis if ((packet->pk_buffer[CF_FLAGS_BYTE_POS])
701b725ae77Skettenis & CF_RESEND) {
702b725ae77Skettenis /* we've been asked for a resend so we had better resend */
703b725ae77Skettenis /*
704b725ae77Skettenis * I don't think we can use a resend as acknowledgement for
705b725ae77Skettenis * anything so lets not do this for the moment
706b725ae77Skettenis * check_seq(msg_home, msg_oppo);
707b725ae77Skettenis */
708b725ae77Skettenis #ifdef RET_DEBUG
709b725ae77Skettenis printf("received a resend request\n");
710b725ae77Skettenis #endif
711b725ae77Skettenis if (HomeSeq != msg_oppo) {
712b725ae77Skettenis int found = FALSE;
713b725ae77Skettenis /* need to resend from msg_oppo +1 upwards */
714b725ae77Skettenis DevSW_FreePacket(packet);
715b725ae77Skettenis resending = TRUE;
716b725ae77Skettenis /* find the correct packet to resend from */
717b725ae77Skettenis packet = writeQueueRoot;
718b725ae77Skettenis while (((packet->pk_next) != NULL) && !found) {
719b725ae77Skettenis if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
720b725ae77Skettenis != msg_oppo+1) {
721b725ae77Skettenis resend_pkt = packet;
722b725ae77Skettenis found = TRUE;
723b725ae77Skettenis }
724b725ae77Skettenis packet = packet->pk_next;
725b725ae77Skettenis }
726b725ae77Skettenis if (!found) {
727b725ae77Skettenis panic("trying to resend non-existent packets\n");
728b725ae77Skettenis }
729b725ae77Skettenis }
730b725ae77Skettenis else if (OppoSeq != msg_home) {
731b725ae77Skettenis /*
732b725ae77Skettenis * send a resend request telling the target where we think
733b725ae77Skettenis * the world is at
734b725ae77Skettenis */
735b725ae77Skettenis DevSW_FreePacket(packet);
736b725ae77Skettenis send_resend_msg(DC_DBUG);
737b725ae77Skettenis }
738b725ae77Skettenis }
739b725ae77Skettenis else {
740b725ae77Skettenis /* not a resend request, lets check the sequence numbers */
741b725ae77Skettenis
742b725ae77Skettenis if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) &&
743b725ae77Skettenis (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) {
744b725ae77Skettenis adp_err = check_seq(msg_home, msg_oppo);
745b725ae77Skettenis if (adp_err == adp_seq_low) {
746b725ae77Skettenis /* we have already received this packet so discard */
747b725ae77Skettenis DevSW_FreePacket(packet);
748b725ae77Skettenis }
749b725ae77Skettenis else if (adp_err == adp_seq_high) {
750b725ae77Skettenis /*
751b725ae77Skettenis * we must have missed a packet somewhere, discard this
752b725ae77Skettenis * packet and tell the target where we are
753b725ae77Skettenis */
754b725ae77Skettenis DevSW_FreePacket(packet);
755b725ae77Skettenis send_resend_msg(DC_DBUG);
756b725ae77Skettenis }
757b725ae77Skettenis else
758b725ae77Skettenis /*
759b725ae77Skettenis * now pass the packet to whoever is waiting for it
760b725ae77Skettenis */
761b725ae77Skettenis FireCallback(packet);
762b725ae77Skettenis }
763b725ae77Skettenis else
764b725ae77Skettenis FireCallback(packet);
765b725ae77Skettenis }
766b725ae77Skettenis }
767b725ae77Skettenis #else
768b725ae77Skettenis /*
769b725ae77Skettenis * now pass the packet to whoever is waiting for it
770b725ae77Skettenis */
771b725ae77Skettenis FireCallback(packet);
772b725ae77Skettenis #endif
773b725ae77Skettenis }
774b725ae77Skettenis }
775b725ae77Skettenis
async_process_appl_read(void)776b725ae77Skettenis static void async_process_appl_read(void)
777b725ae77Skettenis {
778b725ae77Skettenis Packet *packet;
779b725ae77Skettenis AdpErrs adp_err;
780b725ae77Skettenis
781b725ae77Skettenis /* see if there is anything for the DC_APPL channel */
782b725ae77Skettenis adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE);
783b725ae77Skettenis
784b725ae77Skettenis if (adp_err == adp_ok && packet != NULL)
785b725ae77Skettenis {
786b725ae77Skettenis /* got an application packet on a shared device */
787b725ae77Skettenis
788b725ae77Skettenis #ifdef DEBUG
789b725ae77Skettenis printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length);
790b725ae77Skettenis {
791b725ae77Skettenis unsigned int c;
792b725ae77Skettenis for ( c = 0; c < packet->pk_length; ++c )
793b725ae77Skettenis printf( "%02X ", packet->pk_buffer[c] );
794b725ae77Skettenis }
795b725ae77Skettenis printf("\n");
796b725ae77Skettenis #endif
797b725ae77Skettenis
798b725ae77Skettenis if (dc_appl_handler != NULL)
799b725ae77Skettenis {
800b725ae77Skettenis dc_appl_handler( deviceToUse, packet );
801b725ae77Skettenis }
802b725ae77Skettenis else
803b725ae77Skettenis {
804b725ae77Skettenis /* for now, just free it!! */
805b725ae77Skettenis #ifdef DEBUG
806b725ae77Skettenis printf("no handler - dropping DC_APPL packet\n");
807b725ae77Skettenis #endif
808b725ae77Skettenis DevSW_FreePacket( packet );
809b725ae77Skettenis }
810b725ae77Skettenis }
811b725ae77Skettenis }
812b725ae77Skettenis
async_process_write(const AsyncMode mode,bool * const finished)813b725ae77Skettenis static void async_process_write( const AsyncMode mode,
814b725ae77Skettenis bool *const finished )
815b725ae77Skettenis {
816b725ae77Skettenis Packet *packet;
817b725ae77Skettenis
818b725ae77Skettenis #ifdef DEBUG
819b725ae77Skettenis static unsigned int num_written = 0;
820b725ae77Skettenis #endif
821b725ae77Skettenis
822b725ae77Skettenis /*
823b725ae77Skettenis * NOTE: here we rely in the fact that any packet in the writeQueueSend
824b725ae77Skettenis * section of the queue will need its sequence number setting up while
825b725ae77Skettenis * and packet in the writeQueueRoot section will have its sequence
826b725ae77Skettenis * numbers set up from when it was first sent so we can easily look
827b725ae77Skettenis * up the packet numbers when(if) we want to resend the packet.
828b725ae77Skettenis */
829b725ae77Skettenis
830b725ae77Skettenis #ifdef DEBUG
831b725ae77Skettenis if (writeQueueSend!=NULL)
832b725ae77Skettenis printf("written 0x%x\n",num_written += writeQueueSend->pk_length);
833b725ae77Skettenis #endif
834b725ae77Skettenis /*
835b725ae77Skettenis * give the switcher a chance to complete any partial writes
836b725ae77Skettenis */
837b725ae77Skettenis if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy)
838b725ae77Skettenis {
839b725ae77Skettenis /* no point trying a new write */
840b725ae77Skettenis return;
841b725ae77Skettenis }
842b725ae77Skettenis
843b725ae77Skettenis /*
844b725ae77Skettenis * now see whether there is anything to write
845b725ae77Skettenis */
846b725ae77Skettenis packet = NULL;
847b725ae77Skettenis if (resending) {
848b725ae77Skettenis packet = resend_pkt;
849b725ae77Skettenis #ifdef RET_DEBUG
850b725ae77Skettenis printf("resending hseq 0x%x oseq 0x%x\n",
851b725ae77Skettenis packet->pk_buffer[CF_HOME_SEQ_BYTE_POS],
852b725ae77Skettenis packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
853b725ae77Skettenis #endif
854b725ae77Skettenis }
855b725ae77Skettenis else if (writeQueueSend != NULL) {
856b725ae77Skettenis #ifdef RETRANS
857b725ae77Skettenis /* set up the sequence number on the packet */
858b725ae77Skettenis packet = writeQueueSend;
859b725ae77Skettenis HomeSeq++;
860b725ae77Skettenis (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
861b725ae77Skettenis = OppoSeq;
862b725ae77Skettenis (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS])
863b725ae77Skettenis = HomeSeq;
864b725ae77Skettenis (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS])
865b725ae77Skettenis = CF_RELIABLE;
866b725ae77Skettenis # ifdef RET_DEBUG
867b725ae77Skettenis printf("sending packet with hseq 0x%x oseq 0x%x\n",
868b725ae77Skettenis writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS],
869b725ae77Skettenis writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
870b725ae77Skettenis # endif
871b725ae77Skettenis #endif /* RETRANS */
872b725ae77Skettenis }
873b725ae77Skettenis
874b725ae77Skettenis if (packet != NULL) {
875b725ae77Skettenis AdpErrs dev_err;
876b725ae77Skettenis
877b725ae77Skettenis #ifdef FAKE_BAD_LINE_TX
878b725ae77Skettenis fake_bad_line_tx();
879b725ae77Skettenis #endif
880b725ae77Skettenis
881b725ae77Skettenis dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG);
882b725ae77Skettenis if (dev_err == adp_ok) {
883b725ae77Skettenis #ifdef RETRANS
884b725ae77Skettenis if (resending) {
885b725ae77Skettenis /* check to see if we've recovered yet */
886b725ae77Skettenis if ((packet->pk_next) == NULL){
887b725ae77Skettenis # ifdef RET_DEBUG
888b725ae77Skettenis printf("we have recovered\n");
889b725ae77Skettenis # endif
890b725ae77Skettenis resending = FALSE;
891b725ae77Skettenis }
892b725ae77Skettenis else {
893b725ae77Skettenis resend_pkt = resend_pkt->pk_next;
894b725ae77Skettenis }
895b725ae77Skettenis }
896b725ae77Skettenis else {
897b725ae77Skettenis /*
898b725ae77Skettenis * move the packet we just sent from the send queue to the root
899b725ae77Skettenis */
900b725ae77Skettenis Packet *tmp_pkt, *tmp;
901b725ae77Skettenis
902b725ae77Skettenis # ifdef FAKE_BAD_LINE_TX
903b725ae77Skettenis unfake_bad_line_tx();
904b725ae77Skettenis # endif
905b725ae77Skettenis
906b725ae77Skettenis tmp_pkt = writeQueueSend;
907b725ae77Skettenis writeQueueSend = writeQueueSend->pk_next;
908b725ae77Skettenis tmp_pkt->pk_next = NULL;
909b725ae77Skettenis if (writeQueueRoot == NULL)
910b725ae77Skettenis writeQueueRoot = tmp_pkt;
911b725ae77Skettenis else {
912b725ae77Skettenis tmp = writeQueueRoot;
913b725ae77Skettenis while (tmp->pk_next != NULL) {
914b725ae77Skettenis tmp = tmp->pk_next;
915b725ae77Skettenis }
916b725ae77Skettenis tmp->pk_next = tmp_pkt;
917b725ae77Skettenis }
918b725ae77Skettenis }
919b725ae77Skettenis #else /* not RETRANS */
920b725ae77Skettenis /*
921b725ae77Skettenis * switcher has taken the write, so remove it from the
922b725ae77Skettenis * queue, and free its resources
923b725ae77Skettenis */
924b725ae77Skettenis DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend));
925b725ae77Skettenis #endif /* if RETRANS ... else ... */
926b725ae77Skettenis
927b725ae77Skettenis if (mode == async_block_on_write)
928b725ae77Skettenis *finished = DevSW_WriteFinished(deviceToUse);
929b725ae77Skettenis
930b725ae77Skettenis } /* endif write ok */
931b725ae77Skettenis }
932b725ae77Skettenis else /* packet == NULL */
933b725ae77Skettenis {
934b725ae77Skettenis if (mode == async_block_on_write)
935b725ae77Skettenis *finished = DevSW_WriteFinished(deviceToUse);
936b725ae77Skettenis }
937b725ae77Skettenis }
938b725ae77Skettenis
async_process_heartbeat(void)939b725ae77Skettenis static void async_process_heartbeat( void )
940b725ae77Skettenis {
941b725ae77Skettenis /* check to see whether we need to send a heartbeat */
942b725ae77Skettenis gettimeofday(&time_now, NULL);
943b725ae77Skettenis
944b725ae77Skettenis if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE)
945b725ae77Skettenis {
946b725ae77Skettenis /*
947b725ae77Skettenis * if we've not booted then don't do send a heartrate the link
948b725ae77Skettenis * must be reliable enough for us to boot without any clever stuff,
949b725ae77Skettenis * if we can't do this then theres little chance of the link staying
950b725ae77Skettenis * together even with the resends etc
951b725ae77Skettenis */
952b725ae77Skettenis if (heartbeat_enabled) {
953b725ae77Skettenis gettimeofday(&time_lastalive, NULL);
954b725ae77Skettenis pacemaker();
955b725ae77Skettenis }
956b725ae77Skettenis }
957b725ae77Skettenis }
958b725ae77Skettenis
async_process_callbacks(void)959b725ae77Skettenis static void async_process_callbacks( void )
960b725ae77Skettenis {
961b725ae77Skettenis /* call any registered asynchronous callbacks */
962b725ae77Skettenis unsigned int i;
963b725ae77Skettenis for ( i = 0; i < num_async_callbacks; ++i )
964b725ae77Skettenis async_callbacks[i]( deviceToUse, &time_now );
965b725ae77Skettenis }
966b725ae77Skettenis
Adp_AsynchronousProcessing(const AsyncMode mode)967b725ae77Skettenis void Adp_AsynchronousProcessing(const AsyncMode mode)
968b725ae77Skettenis {
969b725ae77Skettenis bool finished = FALSE;
970b725ae77Skettenis #ifdef DEBUG
971b725ae77Skettenis unsigned int wc = 0, dc = 0, ac = 0, hc = 0;
972b725ae77Skettenis # define INC_COUNT(x) ((x)++)
973b725ae77Skettenis #else
974b725ae77Skettenis # define INC_COUNT(x)
975b725ae77Skettenis #endif
976b725ae77Skettenis
977b725ae77Skettenis if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) {
978b725ae77Skettenis /* first time through, needs initing */
979b725ae77Skettenis gettimeofday(&time_lastalive, NULL);
980b725ae77Skettenis }
981b725ae77Skettenis
982b725ae77Skettenis /* main loop */
983b725ae77Skettenis do
984b725ae77Skettenis {
985b725ae77Skettenis async_process_write( mode, &finished );
986b725ae77Skettenis INC_COUNT(wc);
987b725ae77Skettenis
988b725ae77Skettenis if ( ! finished && mode != async_block_on_write )
989b725ae77Skettenis {
990b725ae77Skettenis async_process_dbug_read( mode, &finished );
991b725ae77Skettenis INC_COUNT(dc);
992b725ae77Skettenis }
993b725ae77Skettenis
994b725ae77Skettenis if ( ! finished && mode != async_block_on_write )
995b725ae77Skettenis {
996b725ae77Skettenis async_process_appl_read();
997b725ae77Skettenis INC_COUNT(ac);
998b725ae77Skettenis }
999b725ae77Skettenis
1000b725ae77Skettenis if ( ! finished )
1001b725ae77Skettenis {
1002b725ae77Skettenis if (heartbeat_configured)
1003b725ae77Skettenis async_process_heartbeat();
1004b725ae77Skettenis async_process_callbacks();
1005b725ae77Skettenis INC_COUNT(hc);
1006b725ae77Skettenis }
1007b725ae77Skettenis
1008b725ae77Skettenis } while (!finished && mode != async_block_on_nothing);
1009b725ae77Skettenis
1010b725ae77Skettenis #ifdef DEBUG
1011b725ae77Skettenis if ( mode != async_block_on_nothing )
1012b725ae77Skettenis printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1013b725ae77Skettenis mode == async_block_on_write ? "blk_write" : "blk_read",
1014b725ae77Skettenis wc, dc, ac, hc );
1015b725ae77Skettenis #endif
1016b725ae77Skettenis }
1017b725ae77Skettenis
1018b725ae77Skettenis /*
1019b725ae77Skettenis * install a handler for DC_APPL packets (can be NULL), returning old one.
1020b725ae77Skettenis */
Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)1021b725ae77Skettenis DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)
1022b725ae77Skettenis {
1023b725ae77Skettenis DC_Appl_Handler old_handler = dc_appl_handler;
1024b725ae77Skettenis
1025b725ae77Skettenis #ifdef DEBUG
1026b725ae77Skettenis printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler );
1027b725ae77Skettenis #endif
1028b725ae77Skettenis
1029b725ae77Skettenis dc_appl_handler = handler;
1030b725ae77Skettenis return old_handler;
1031b725ae77Skettenis }
1032b725ae77Skettenis
1033b725ae77Skettenis
1034b725ae77Skettenis /*
1035b725ae77Skettenis * add an asynchronous processing callback to the list
1036b725ae77Skettenis * TRUE == okay, FALSE == no more async processing slots
1037b725ae77Skettenis */
Adp_Install_Async_Callback(const Adp_Async_Callback callback_proc)1038b725ae77Skettenis bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc )
1039b725ae77Skettenis {
1040b725ae77Skettenis if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL )
1041b725ae77Skettenis {
1042b725ae77Skettenis async_callbacks[num_async_callbacks] = callback_proc;
1043b725ae77Skettenis ++num_async_callbacks;
1044b725ae77Skettenis return TRUE;
1045b725ae77Skettenis }
1046b725ae77Skettenis else
1047b725ae77Skettenis return FALSE;
1048b725ae77Skettenis }
1049b725ae77Skettenis
1050b725ae77Skettenis
1051b725ae77Skettenis /*
1052b725ae77Skettenis * delay for a given period (in microseconds)
1053b725ae77Skettenis */
Adp_delay(unsigned int period)1054b725ae77Skettenis void Adp_delay(unsigned int period)
1055b725ae77Skettenis {
1056b725ae77Skettenis struct timeval tv;
1057b725ae77Skettenis
1058b725ae77Skettenis #ifdef DEBUG
1059b725ae77Skettenis printf("delaying for %d microseconds\n", period);
1060b725ae77Skettenis #endif
1061b725ae77Skettenis tv.tv_sec = (period / 1000000);
1062b725ae77Skettenis tv.tv_usec = (period % 1000000);
1063b725ae77Skettenis
1064b725ae77Skettenis (void)select(0, NULL, NULL, NULL, &tv);
1065b725ae77Skettenis }
1066b725ae77Skettenis
1067b725ae77Skettenis /* EOF hostchan.c */
1068