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