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