1/*
2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3 *
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
6 * software.
7 */
8
9/* -*-C-*-
10 *
11 * $Revision: 1.8 $
12 *     $Date: 2000/01/20 16:08:00 $
13 *
14 */
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <fcntl.h>
19#include <time.h>
20
21#include "adp.h"
22#include "sys.h"
23#include "hsys.h"
24#include "rxtx.h"
25#include "drivers.h"
26#include "buffers.h"
27#include "devclnt.h"
28#include "adperr.h"
29#include "devsw.h"
30#include "hostchan.h"
31#include "logging.h"
32
33static char *angelDebugFilename = NULL;
34static FILE *angelDebugLogFile = NULL;
35static int angelDebugLogEnable = 0;
36
37static void openLogFile ()
38{
39  time_t t;
40
41  if (angelDebugFilename == NULL || *angelDebugFilename =='\0')
42    return;
43
44  angelDebugLogFile = fopen (angelDebugFilename,"a");
45
46  if (!angelDebugLogFile)
47    {
48      fprintf (stderr,"Error opening log file '%s'\n",angelDebugFilename);
49      perror ("fopen");
50    }
51  else
52    {
53      /* The following line is equivalent to: */
54      /* setlinebuf (angelDebugLogFile); */
55      setvbuf(angelDebugLogFile, (char *)NULL, _IOLBF, 0);
56#if defined(__CYGWIN__)
57      setmode(fileno(angelDebugLogFile), O_TEXT);
58#endif
59    }
60
61  time (&t);
62  fprintf (angelDebugLogFile,"ADP log file opened at %s\n",asctime(localtime(&t)));
63}
64
65
66static void closeLogFile (void)
67{
68  time_t t;
69
70  if (!angelDebugLogFile)
71    return;
72
73  time (&t);
74  fprintf (angelDebugLogFile,"ADP log file closed at %s\n",asctime(localtime(&t)));
75
76  fclose (angelDebugLogFile);
77  angelDebugLogFile = NULL;
78}
79
80void DevSW_SetLogEnable (int logEnableFlag)
81{
82  if (logEnableFlag && !angelDebugLogFile)
83    openLogFile ();
84  else if (!logEnableFlag && angelDebugLogFile)
85    closeLogFile ();
86
87  angelDebugLogEnable = logEnableFlag;
88}
89
90
91void DevSW_SetLogfile (const char *filename)
92{
93  closeLogFile ();
94
95  if (angelDebugFilename)
96    {
97      free (angelDebugFilename);
98      angelDebugFilename = NULL;
99    }
100
101  if (filename && *filename)
102    {
103      angelDebugFilename = strdup (filename);
104      if (angelDebugLogEnable)
105        openLogFile ();
106    }
107}
108
109
110#define WordAt(p)  ((unsigned long) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24)))
111
112static void dumpPacket(FILE *fp, char *label, struct data_packet *p)
113{
114  unsigned r;
115  int i;
116  unsigned char channel;
117
118  if (!fp)
119    return;
120
121  fprintf(fp,"%s [T=%d L=%d] ",label,p->type,p->len);
122  for (i=0; i<p->len; ++i)
123    fprintf(fp,"%02x ",p->data[i]);
124  fprintf(fp,"\n");
125
126  channel = p->data[0];
127
128  r = WordAt(p->data+4);
129
130  fprintf(fp,"R=%08x ",r);
131  fprintf(fp,"%s ", r&0x80000000 ? "H<-T" : "H->T");
132
133  switch (channel)
134    {
135     case CI_PRIVATE: fprintf(fp,"CI_PRIVATE: "); break;
136     case CI_HADP: fprintf(fp,"CI_HADP: "); break;
137     case CI_TADP: fprintf(fp,"CI_TADP: "); break;
138     case CI_HBOOT: fprintf(fp,"CI_HBOOT: "); break;
139     case CI_TBOOT: fprintf(fp,"CI_TBOOT: "); break;
140     case CI_CLIB: fprintf(fp,"CI_CLIB: "); break;
141     case CI_HUDBG: fprintf(fp,"CI_HUDBG: "); break;
142     case CI_TUDBG: fprintf(fp,"CI_TUDBG: "); break;
143     case CI_HTDCC: fprintf(fp,"CI_HTDCC: "); break;
144     case CI_TTDCC: fprintf(fp,"CI_TTDCC: "); break;
145     case CI_TLOG: fprintf(fp,"CI_TLOG: "); break;
146     default:      fprintf(fp,"BadChan: "); break;
147    }
148
149  switch (r & 0xffffff)
150    {
151     case ADP_Booted: fprintf(fp," ADP_Booted "); break;
152#if defined(ADP_TargetResetIndication)
153     case ADP_TargetResetIndication: fprintf(fp," ADP_TargetResetIndication "); break;
154#endif
155     case ADP_Reboot: fprintf(fp," ADP_Reboot "); break;
156     case ADP_Reset: fprintf(fp," ADP_Reset "); break;
157#if defined(ADP_HostResetIndication)
158     case ADP_HostResetIndication: fprintf(fp," ADP_HostResetIndication "); break;
159#endif
160     case ADP_ParamNegotiate: fprintf(fp," ADP_ParamNegotiate "); break;
161     case ADP_LinkCheck: fprintf(fp," ADP_LinkCheck "); break;
162     case ADP_HADPUnrecognised: fprintf(fp," ADP_HADPUnrecognised "); break;
163     case ADP_Info: fprintf(fp," ADP_Info "); break;
164     case ADP_Control: fprintf(fp," ADP_Control "); break;
165     case ADP_Read: fprintf(fp," ADP_Read "); break;
166     case ADP_Write: fprintf(fp," ADP_Write "); break;
167     case ADP_CPUread: fprintf(fp," ADP_CPUread "); break;
168     case ADP_CPUwrite: fprintf(fp," ADP_CPUwrite "); break;
169     case ADP_CPread: fprintf(fp," ADP_CPread "); break;
170     case ADP_CPwrite: fprintf(fp," ADP_CPwrite "); break;
171     case ADP_SetBreak: fprintf(fp," ADP_SetBreak "); break;
172     case ADP_ClearBreak: fprintf(fp," ADP_ClearBreak "); break;
173     case ADP_SetWatch: fprintf(fp," ADP_SetWatch "); break;
174     case ADP_ClearWatch: fprintf(fp," ADP_ClearWatch "); break;
175     case ADP_Execute: fprintf(fp," ADP_Execute "); break;
176     case ADP_Step: fprintf(fp," ADP_Step "); break;
177     case ADP_InterruptRequest: fprintf(fp," ADP_InterruptRequest "); break;
178     case ADP_HW_Emulation: fprintf(fp," ADP_HW_Emulation "); break;
179     case ADP_ICEbreakerHADP: fprintf(fp," ADP_ICEbreakerHADP "); break;
180     case ADP_ICEman: fprintf(fp," ADP_ICEman "); break;
181     case ADP_Profile: fprintf(fp," ADP_Profile "); break;
182     case ADP_InitialiseApplication: fprintf(fp," ADP_InitialiseApplication "); break;
183     case ADP_End: fprintf(fp," ADP_End "); break;
184     case ADP_TADPUnrecognised: fprintf(fp," ADP_TADPUnrecognised "); break;
185     case ADP_Stopped: fprintf(fp," ADP_Stopped "); break;
186     case ADP_TDCC_ToHost: fprintf(fp," ADP_TDCC_ToHost "); break;
187     case ADP_TDCC_FromHost: fprintf(fp," ADP_TDCC_FromHost "); break;
188
189     case CL_Unrecognised: fprintf(fp," CL_Unrecognised "); break;
190     case CL_WriteC: fprintf(fp," CL_WriteC "); break;
191     case CL_Write0: fprintf(fp," CL_Write0 "); break;
192     case CL_ReadC: fprintf(fp," CL_ReadC "); break;
193     case CL_System: fprintf(fp," CL_System "); break;
194     case CL_GetCmdLine: fprintf(fp," CL_GetCmdLine "); break;
195     case CL_Clock: fprintf(fp," CL_Clock "); break;
196     case CL_Time: fprintf(fp," CL_Time "); break;
197     case CL_Remove: fprintf(fp," CL_Remove "); break;
198     case CL_Rename: fprintf(fp," CL_Rename "); break;
199     case CL_Open: fprintf(fp," CL_Open "); break;
200     case CL_Close: fprintf(fp," CL_Close "); break;
201     case CL_Write: fprintf(fp," CL_Write "); break;
202     case CL_WriteX: fprintf(fp," CL_WriteX "); break;
203     case CL_Read: fprintf(fp," CL_Read "); break;
204     case CL_ReadX: fprintf(fp," CL_ReadX "); break;
205     case CL_Seek: fprintf(fp," CL_Seek "); break;
206     case CL_Flen: fprintf(fp," CL_Flen "); break;
207     case CL_IsTTY: fprintf(fp," CL_IsTTY "); break;
208     case CL_TmpNam: fprintf(fp," CL_TmpNam "); break;
209
210     default: fprintf(fp," BadReason "); break;
211    }
212
213  i = 20;
214
215  if (((r & 0xffffff) == ADP_CPUread ||
216       (r & 0xffffff) == ADP_CPUwrite) && (r&0x80000000)==0)
217    {
218      fprintf(fp,"%02x ", p->data[i]);
219      ++i;
220    }
221
222  for (; i<p->len; i+=4)
223    fprintf(fp,"%08x ",WordAt(p->data+i));
224
225  fprintf(fp,"\n");
226}
227
228
229/*
230 * TODO: this should be adjustable - it could be done by defining
231 *       a reason code for DevSW_Ioctl.  It could even be a
232 *       per-devicechannel parameter.
233 */
234static const unsigned int allocsize = ADP_BUFFER_MIN_SIZE;
235
236#define illegalDevChanID(type)  ((type) >= DC_NUM_CHANNELS)
237
238/**********************************************************************/
239
240/*
241 *  Function: initialise_read
242 *   Purpose: Set up a read request for another packet
243 *
244 *    Params:
245 *      In/Out: ds      State structure to be initialised
246 *
247 *   Returns:
248 *          OK: 0
249 *       Error: -1
250 */
251static int initialise_read(DevSWState *ds)
252{
253    struct data_packet *dp;
254
255    /*
256     * try to claim the structure that will
257     * eventually hold the new packet.
258     */
259    if ((ds->ds_nextreadpacket = DevSW_AllocatePacket(allocsize)) == NULL)
260        return -1;
261
262    /*
263     * Calls into the device driver use the DriverCall structure: use
264     * the buffer we have just allocated, and declare its size.  We
265     * are also obliged to clear the driver's context pointer.
266     */
267    dp = &ds->ds_activeread.dc_packet;
268    dp->buf_len = allocsize;
269    dp->data = ds->ds_nextreadpacket->pk_buffer;
270
271    ds->ds_activeread.dc_context = NULL;
272
273    return 0;
274}
275
276/*
277 *  Function: initialise_write
278 *   Purpose: Set up a write request for another packet
279 *
280 *    Params:
281 *       Input: packet  The packet to be written
282 *
283 *              type    The type of the packet
284 *
285 *      In/Out: dc      The structure to be intialised
286 *
287 *   Returns: Nothing
288 */
289static void initialise_write(DriverCall *dc, Packet *packet, DevChanID type)
290{
291    struct data_packet *dp = &dc->dc_packet;
292
293    dp->len = packet->pk_length;
294    dp->data = packet->pk_buffer;
295    dp->type = type;
296
297    /*
298     * we are required to clear the state structure for the driver
299     */
300    dc->dc_context = NULL;
301}
302
303/*
304 *  Function: enqueue_packet
305 *   Purpose: move a newly read packet onto the appropriate queue
306 *              of read packets
307 *
308 *    Params:
309 *      In/Out: ds      State structure with new packet
310 *
311 *   Returns: Nothing
312 */
313static void enqueue_packet(DevSWState *ds)
314{
315    struct data_packet *dp = &ds->ds_activeread.dc_packet;
316    Packet *packet = ds->ds_nextreadpacket;
317
318    /*
319     * transfer the length
320     */
321    packet->pk_length = dp->len;
322
323    /*
324     * take this packet out of the incoming slot
325     */
326    ds->ds_nextreadpacket = NULL;
327
328    /*
329     * try to put it on the correct input queue
330     */
331    if (illegalDevChanID(dp->type))
332    {
333        /* this shouldn't happen */
334        WARN("Illegal type for Rx packet");
335        DevSW_FreePacket(packet);
336    }
337    else
338        Adp_addToQueue(&ds->ds_readqueue[dp->type], packet);
339}
340
341/*
342 *  Function: flush_packet
343 *   Purpose: Send a packet to the device driver
344 *
345 *    Params:
346 *       Input: device  The device to be written to
347 *
348 *      In/Out: dc      Describes the packet to be sent
349 *
350 *   Returns: Nothing
351 *
352 * Post-conditions: If the whole packet was accepted by the device
353 *                      driver, then dc->dc_packet.data will be
354 *                      set to NULL.
355 */
356static void flush_packet(const DeviceDescr *device, DriverCall *dc)
357{
358    if (device->DeviceWrite(dc) > 0)
359        /*
360         * the whole packet was swallowed
361         */
362        dc->dc_packet.data = NULL;
363}
364
365/**********************************************************************/
366
367/*
368 * These are the externally visible functions.  They are documented in
369 * devsw.h
370 */
371Packet *DevSW_AllocatePacket(const unsigned int length)
372{
373    Packet *pk;
374
375    if ((pk = malloc(sizeof(*pk))) == NULL)
376    {
377        WARN("malloc failure");
378        return NULL;
379    }
380
381    if ((pk->pk_buffer = malloc(length+CHAN_HEADER_SIZE)) == NULL)
382    {
383        WARN("malloc failure");
384        free(pk);
385        return NULL;
386    }
387
388    return pk;
389}
390
391void DevSW_FreePacket(Packet *pk)
392{
393    free(pk->pk_buffer);
394    free(pk);
395}
396
397AdpErrs DevSW_Open(DeviceDescr *device, const char *name, const char *arg,
398                   const DevChanID type)
399{
400    DevSWState *ds;
401
402    /*
403     * is this the very first open call for this driver?
404     */
405    if ((ds = (DevSWState *)(device->SwitcherState)) == NULL)
406    {
407        /*
408         * yes, it is: initialise state
409         */
410        if ((ds = malloc(sizeof(*ds))) == NULL)
411            /* give up */
412            return adp_malloc_failure;
413
414        (void)memset(ds, 0, sizeof(*ds));
415        device->SwitcherState = (void *)ds;
416    }
417
418    /*
419     * check that we haven't already been opened for this type
420     */
421    if ((ds->ds_opendevchans & (1 << type)) != 0)
422        return adp_device_already_open;
423
424    /*
425     * if no opens have been done for this device, then do it now
426     */
427    if (ds->ds_opendevchans == 0)
428        if (device->DeviceOpen(name, arg) < 0)
429            return adp_device_open_failed;
430
431    /*
432     * open has finished
433     */
434    ds->ds_opendevchans |= (1 << type);
435    return adp_ok;
436}
437
438AdpErrs DevSW_Match(const DeviceDescr *device, const char *name,
439                    const char *arg)
440{
441    return (device->DeviceMatch(name, arg) == -1) ? adp_failed : adp_ok;
442}
443
444AdpErrs DevSW_Close (DeviceDescr *device, const DevChanID type)
445{
446    DevSWState *ds = (DevSWState *)(device->SwitcherState);
447    Packet *pk;
448
449    if ((ds->ds_opendevchans & (1 << type)) == 0)
450        return adp_device_not_open;
451
452    ds->ds_opendevchans &= ~(1 << type);
453
454    /*
455     * if this is the last close for this channel, then inform the driver
456     */
457    if (ds->ds_opendevchans == 0)
458        device->DeviceClose();
459
460    /*
461     * release all packets of the appropriate type
462     */
463    for (pk = Adp_removeFromQueue(&(ds->ds_readqueue[type]));
464         pk != NULL;
465         pk = Adp_removeFromQueue(&(ds->ds_readqueue[type])))
466        DevSW_FreePacket(pk);
467
468    /* Free memory */
469    free ((char *) device->SwitcherState);
470    device->SwitcherState = 0x0;
471
472    /* that's all */
473    return adp_ok;
474}
475
476AdpErrs DevSW_Read(const DeviceDescr *device, const DevChanID type,
477                   Packet **packet, bool block)
478{
479  int read_err;
480  DevSWState *ds = device->SwitcherState;
481
482    /*
483     * To try to get information out of the device driver as
484     * quickly as possible, we try and read more packets, even
485     * if a completed packet is already available.
486     */
487
488    /*
489     * have we got a packet currently pending?
490     */
491  if (ds->ds_nextreadpacket == NULL)
492    /*
493       * no - set things up
494       */
495    if (initialise_read(ds) < 0) {
496      /*
497       * we failed to initialise the next packet, but can
498       * still return a packet that has already arrived.
499       */
500      *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
501      return adp_ok;
502    }
503  read_err = device->DeviceRead(&ds->ds_activeread, block);
504  switch (read_err) {
505  case 1:
506    /*
507     * driver has pulled in a complete packet, queue it up
508     */
509#ifdef RET_DEBUG
510    printf("got a complete packet\n");
511#endif
512
513    if (angelDebugLogEnable)
514      dumpPacket(angelDebugLogFile,"rx:",&ds->ds_activeread.dc_packet);
515
516    enqueue_packet(ds);
517    *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
518    return adp_ok;
519  case 0:
520    /*
521     * OK, return the head of the read queue for the given type
522     */
523    /*    enqueue_packet(ds); */
524    *packet = Adp_removeFromQueue(&ds->ds_readqueue[type]);
525    return adp_ok;
526  case -1:
527#ifdef RET_DEBUG
528    printf("got a bad packet\n");
529#endif
530    /* bad packet */
531    *packet = NULL;
532    return adp_bad_packet;
533  default:
534    panic("DevSW_Read: bad read status %d", read_err);
535  }
536  return 0; /* get rid of a potential compiler warning */
537}
538
539
540AdpErrs DevSW_FlushPendingWrite(const DeviceDescr *device)
541{
542    struct DriverCall *dc;
543    struct data_packet *dp;
544
545    dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
546    dp = &dc->dc_packet;
547
548    /*
549     * try to flush any packet that is still being written
550     */
551    if (dp->data != NULL)
552    {
553        flush_packet(device, dc);
554
555        /* see if it has gone */
556        if (dp->data != NULL)
557           return adp_write_busy;
558        else
559           return adp_ok;
560    }
561    else
562       return adp_ok;
563}
564
565
566AdpErrs DevSW_Write(const DeviceDescr *device, Packet *packet, DevChanID type)
567{
568    struct DriverCall *dc;
569    struct data_packet *dp;
570
571    dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
572    dp = &dc->dc_packet;
573
574    if (illegalDevChanID(type))
575        return adp_illegal_args;
576
577    /*
578     * try to flush any packet that is still being written
579     */
580    if (DevSW_FlushPendingWrite(device) != adp_ok)
581       return adp_write_busy;
582
583    /*
584     * we can take this packet - set things up, then try to get rid of it
585     */
586    initialise_write(dc, packet, type);
587
588    if (angelDebugLogEnable)
589      dumpPacket(angelDebugLogFile,"tx:",&dc->dc_packet);
590
591    flush_packet(device, dc);
592
593    return adp_ok;
594}
595
596AdpErrs DevSW_Ioctl(const DeviceDescr *device, const int opcode, void *args)
597{
598    return (device->DeviceIoctl(opcode, args) < 0) ? adp_failed : adp_ok;
599}
600
601bool DevSW_WriteFinished(const DeviceDescr *device)
602{
603    struct DriverCall *dc;
604    struct data_packet *dp;
605
606    dc = &((DevSWState *)(device->SwitcherState))->ds_activewrite;
607    dp = &dc->dc_packet;
608
609    return (dp == NULL || dp->data == NULL);
610}
611
612/* EOF devsw.c */
613