xref: /openbsd-src/gnu/usr.bin/binutils/gdb/rdi-share/hostchan.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
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