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.3 $
12  *     $Date: 2004/12/27 14:00:54 $
13  *
14  *
15  * serpardv.c - Serial/Parallel Driver for Angel.
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "crc.h"
22 #include "devices.h"
23 #include "buffers.h"
24 #include "rxtx.h"
25 #include "hostchan.h"
26 #include "params.h"
27 #include "logging.h"
28 #include "hsys.h"
29 
30 #ifdef COMPILING_ON_WINDOWS
31 #  undef   ERROR
32 #  undef   IGNORE
33 #  include <windows.h>
34 #  include "angeldll.h"
35 #  include "comb_api.h"
36 #else
37 #  ifdef __hpux
38 #    define _TERMIOS_INCLUDED
39 #    include <sys/termio.h>
40 #    undef _TERMIOS_INCLUDED
41 #  else
42 #    include <termios.h>
43 #  endif
44 #  include "unixcomm.h"
45 #endif
46 
47 #ifndef UNUSED
48 #  define UNUSED(x) (x = x)     /* Silence compiler warnings */
49 #endif
50 
51 #define MAXREADSIZE     512
52 #define MAXWRITESIZE    512
53 
54 #define SERPAR_FC_SET  ((1 << serial_XON) | (1 << serial_XOFF))
55 #define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \
56                         (1 << serial_ESC))
57 #define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET)
58 
59 static const struct re_config config = {
60     serial_STX, serial_ETX, serial_ESC, /* self-explanatory?               */
61     SERPAR_FC_SET,                      /* set of flow-control characters  */
62     SERPAR_ESC_SET,                     /* set of characters to be escaped */
63     NULL,                               /* serial_flow_control */
64     NULL,                               /* what to do with FC chars */
65     angel_DD_RxEng_BufferAlloc, NULL    /* how to get a buffer */
66 };
67 
68 static struct re_state rxstate;
69 
70 /*
71  * structure used for manipulating transmit data
72  */
73 typedef struct TxState
74 {
75     struct te_state state;
76     unsigned int    index;
77     unsigned char   writebuf[MAXWRITESIZE];
78 } TxState;
79 
80 /*
81  * The set of parameter options supported by the device
82  */
83 static unsigned int baud_options[] =
84 {
85 #ifdef __hpux
86     115200, 57600,
87 #endif
88     38400, 19200, 9600
89 };
90 
91 static ParameterList param_list[] =
92 {
93     {
94         AP_BAUD_RATE,
95         sizeof(baud_options) / sizeof(unsigned int),
96         baud_options
97     }
98 };
99 
100 static const ParameterOptions serpar_options =
101 {
102     sizeof(param_list) / sizeof(ParameterList),
103     param_list
104 };
105 
106 /*
107  * The default parameter config for the device
108  */
109 static Parameter param_default[] =
110 {
111     { AP_BAUD_RATE, 9600 }
112 };
113 
114 static const ParameterConfig serpar_defaults =
115 {
116     sizeof(param_default)/sizeof(Parameter),
117     param_default
118 };
119 
120 /*
121  * The user-modified options for the device
122  */
123 static unsigned int user_baud_options[sizeof(baud_options) /
124                                      sizeof(unsigned int)];
125 
126 static ParameterList param_user_list[] =
127 {
128     {
129         AP_BAUD_RATE,
130         sizeof(user_baud_options) / sizeof(unsigned),
131         user_baud_options
132     }
133 };
134 
135 static ParameterOptions user_options =
136 {
137     sizeof(param_user_list) / sizeof(ParameterList),
138     param_user_list
139 };
140 
141 static bool user_options_set;
142 
143 /* forward declarations */
144 static int serpar_reset(void);
145 static int serpar_set_params(const ParameterConfig *config);
146 static int SerparMatch(const char *name, const char *arg);
147 
process_baud_rate(unsigned int target_baud_rate)148 static void process_baud_rate(unsigned int target_baud_rate)
149 {
150     const ParameterList *full_list;
151     ParameterList       *user_list;
152 
153     /* create subset of full options */
154     full_list = Angel_FindParamList(&serpar_options, AP_BAUD_RATE);
155     user_list = Angel_FindParamList(&user_options,   AP_BAUD_RATE);
156 
157     if (full_list != NULL && user_list != NULL)
158     {
159         unsigned int i, j;
160         unsigned int def_baud = 0;
161 
162         /* find lower or equal to */
163         for (i = 0; i < full_list->num_options; ++i)
164            if (target_baud_rate >= full_list->option[i])
165            {
166                /* copy remaining */
167                for (j = 0; j < (full_list->num_options - i); ++j)
168                   user_list->option[j] = full_list->option[i+j];
169                user_list->num_options = j;
170 
171                /* check this is not the default */
172                Angel_FindParam(AP_BAUD_RATE, &serpar_defaults, &def_baud);
173                if ((j == 1) && (user_list->option[0] == def_baud))
174                {
175 #ifdef DEBUG
176                    printf("user selected default\n");
177 #endif
178                }
179                else
180                {
181                    user_options_set = TRUE;
182 #ifdef DEBUG
183                    printf("user options are: ");
184                    for (j = 0; j < user_list->num_options; ++j)
185                       printf("%u ", user_list->option[j]);
186                    printf("\n");
187 #endif
188                }
189 
190                break;   /* out of i loop */
191            }
192 
193 #ifdef DEBUG
194         if (i >= full_list->num_options)
195            printf("couldn't match baud rate %u\n", target_baud_rate);
196 #endif
197     }
198 #ifdef DEBUG
199     else
200        printf("failed to find lists\n");
201 #endif
202 }
203 
SerparOpen(const char * name,const char * arg)204 static int SerparOpen(const char *name, const char *arg)
205 {
206     char *sername = NULL;
207     char *parname = NULL;
208 
209 #ifdef DEBUG
210     printf("SerparOpen: name %s arg %s\n", name, arg ? arg : "<NULL>");
211 #endif
212 
213 #ifdef COMPILING_ON_WINDOWS
214     if (IsOpenSerial() || IsOpenParallel()) return -1;
215 #else
216     if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1;
217 #endif
218 
219 #ifdef COMPILING_ON_WINDOWS
220     if (SerparMatch(name, arg) == -1)
221         return -1;
222 #else
223     Unix_IsValidParallelDevice(name,&sername,&parname);
224 # ifdef DEBUG
225     printf("translated %s to serial %s and parallel %s\n",
226            name==0 ? "NULL" : name,
227            sername==0 ? "NULL" : sername,
228            parname==0 ? "NULL" : parname);
229 # endif
230     if (sername==NULL || parname==NULL) return -1;
231 #endif
232 
233     user_options_set = FALSE;
234 
235     /* interpret and store the arguments */
236     if (arg != NULL)
237     {
238         unsigned int target_baud_rate;
239 
240         target_baud_rate = (unsigned int)strtoul(arg, NULL, 10);
241 
242         if (target_baud_rate > 0)
243         {
244 #ifdef DEBUG
245             printf("user selected baud rate %u\n", target_baud_rate);
246 #endif
247             process_baud_rate(target_baud_rate);
248         }
249 #ifdef DEBUG
250         else
251             printf("could not understand baud rate %s\n", arg);
252 #endif
253     }
254 
255 #ifdef COMPILING_ON_WINDOWS
256     {
257         /*
258          * The serial port number is in name[0] followed by
259          * the parallel port number in name[1]
260          */
261 
262         int sport = name[0] - '0';
263         int pport = name[1] - '0';
264 
265         if (OpenParallel(pport) != COM_OK)
266             return -1;
267 
268         if (OpenSerial(sport, FALSE) != COM_OK)
269         {
270             CloseParallel();
271             return -1;
272         }
273     }
274 #else
275     Unix_OpenParallel(parname);
276     Unix_OpenSerial(sername);
277 #endif
278 
279     serpar_reset();
280 
281 #if defined(__unix) || defined(__CYGWIN__)
282     Unix_ioctlNonBlocking();
283 #endif
284 
285     Angel_RxEngineInit(&config, &rxstate);
286 
287     return 0;
288 }
289 
290 #ifdef COMPILING_ON_WINDOWS
SerparMatch(const char * name,const char * arg)291 static int SerparMatch(const char *name, const char *arg)
292 {
293     char sername[2];
294     char parname[2];
295 
296     UNUSED(arg);
297 
298     sername[0] = name[0];
299     parname[0] = name[1];
300     sername[1] = parname[1] = 0;
301 
302     if (IsValidDevice(sername) == COM_DEVICENOTVALID ||
303         IsValidDevice(parname) == COM_DEVICENOTVALID)
304         return -1;
305     else
306         return 0;
307 }
308 #else
SerparMatch(const char * portstring,const char * arg)309 static int SerparMatch(const char *portstring, const char *arg)
310 {
311     char *sername=NULL, *parname=NULL;
312     UNUSED(arg);
313 
314     Unix_IsValidParallelDevice(portstring,&sername,&parname);
315 
316       /* Match failed if either sername or parname are still NULL */
317     if (sername==NULL || parname==NULL) return -1;
318     return 0;
319 }
320 #endif
321 
SerparClose(void)322 static void SerparClose(void)
323 {
324 #ifdef COMPILING_ON_WINDOWS
325     CloseParallel();
326     CloseSerial();
327 #else
328     Unix_CloseParallel();
329     Unix_CloseSerial();
330 #endif
331 }
332 
SerparRead(DriverCall * dc,bool block)333 static int SerparRead(DriverCall *dc, bool block)
334 {
335     static unsigned char readbuf[MAXREADSIZE];
336     static int rbindex = 0;
337 
338     int nread;
339     int read_errno;
340     int c = 0;
341     re_status restatus;
342     int ret_code = -1;            /* assume bad packet or error */
343 
344     /*
345      * we must not overflow buffer, and must start after
346      * the existing data
347      */
348 #ifdef COMPILING_ON_WINDOWS
349     {
350         BOOL dummy = FALSE;
351         nread = BytesInRXBufferSerial();
352 
353         if (nread > MAXREADSIZE - rbindex)
354             nread = MAXREADSIZE - rbindex;
355         read_errno = ReadSerial(readbuf+rbindex, nread, &dummy);
356         if (pfnProgressCallback != NULL && read_errno == COM_OK)
357         {
358             progressInfo.nRead += nread;
359             (*pfnProgressCallback)(&progressInfo);
360         }
361     }
362 #else
363     nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block);
364     read_errno = errno;
365 #endif
366 
367     if ((nread > 0) || (rbindex > 0))
368     {
369 #ifdef DO_TRACE
370         printf("[%d@%d] ", nread, rbindex);
371 #endif
372 
373         if (nread > 0)
374             rbindex = rbindex + nread;
375 
376         do
377         {
378             restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate);
379 
380 #ifdef DO_TRACE
381             printf("<%02X ",readbuf[c]);
382 #endif
383             c++;
384         } while (c < rbindex &&
385                  ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT)));
386 
387 #ifdef DO_TRACE
388         printf("\n");
389 #endif
390 
391         switch(restatus)
392         {
393           case RS_GOOD_PKT:
394               ret_code = 1;
395               /* fall through to: */
396 
397           case RS_BAD_PKT:
398               /*
399                * We now need to shuffle any left over data down to the
400                * beginning of our private buffer ready to be used
401                *for the next packet
402                */
403 #ifdef DO_TRACE
404               printf("SerparRead() processed %d, moving down %d\n",
405                      c, rbindex - c);
406 #endif
407 
408               if (c != rbindex)
409                   memmove((char *) readbuf, (char *) (readbuf + c), rbindex - c);
410 
411               rbindex -= c;
412 
413               break;
414 
415           case RS_IN_PKT:
416           case RS_WAIT_PKT:
417               rbindex = 0;            /* will have processed all we had */
418               ret_code = 0;
419               break;
420 
421           default:
422 #ifdef DEBUG
423               printf("Bad re_status in SerparRead()\n");
424 #endif
425               break;
426         }
427     }
428     else if (nread == 0)
429         /* nothing to read */
430         ret_code = 0;
431     else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */
432         ret_code = 0;
433 
434 #ifdef DEBUG
435     if ((nread < 0) && (read_errno != ERRNO_FOR_BLOCKED_IO))
436         perror("read() error in SerparRead()");
437 #endif
438 
439     return ret_code;
440 }
441 
442 /*
443  *  Function: send_packet
444  *   Purpose: Send a stream of bytes to Angel through the parallel port
445  *
446  * Algorithm: We need to present the data in a form that all boards can
447  *            swallow.  With the PID board, this is a problem: for reasons
448  *            described in the driver (angel/pid/st16c552.c), data are
449  *            sent a nybble at a time on D0-D2 and D4; D3 is wired to ACK,
450  *            which generates an interrupt when it goes low.  This routine
451  *            fills in an array of nybbles, with ACK clear in all but the
452  *            last one.  If, for whatever reason, the write fails, then
453  *            ACK is forced high (thereby enabling the next write a chance
454  *            to be noticed when the falling edge of ACK generates an
455  *            interrupt (hopefully).
456  *
457  *    Params:
458  *       Input: txstate Contains the packet to be sent
459  *
460  *   Returns: Number of *complete* bytes written
461  */
462 
SerparWrite(DriverCall * dc)463 static int SerparWrite(DriverCall *dc)
464 {
465     te_status status;
466     int nwritten = 0;
467     static TxState txstate;
468 
469     /*
470      * is this a new packet?
471      */
472     if (dc->dc_context == NULL)
473     {
474         /*
475          * yes - initialise TxEngine
476          */
477         Angel_TxEngineInit(&config, &dc->dc_packet, &txstate.state);
478 
479         txstate.index = 0;
480         dc->dc_context = &txstate;
481     }
482 
483     /*
484      * fill the buffer using the Tx Engine
485      */
486     do
487     {
488         status = Angel_TxEngine(&dc->dc_packet, &txstate.state,
489                                 &txstate.writebuf[txstate.index]);
490         if (status != TS_IDLE) txstate.index++;
491 
492     } while (status == TS_IN_PKT && txstate.index < MAXWRITESIZE);
493 
494 #ifdef DO_TRACE
495     {
496         unsigned int i = 0;
497 
498         while (i < txstate.index)
499         {
500             printf(">%02X ", txstate.writebuf[i]);
501 
502             if (!(++i % 16))
503                 putc('\n', stdout);
504         }
505 
506         if (i % 16)
507             putc('\n', stdout);
508     }
509 #endif
510 
511     /*
512      * the data are ready, all we need now is to send them out
513      * in a form that Angel can swallow.
514      */
515 #ifdef COMPILING_ON_WINDOWS
516   if (WriteParallel(txstate.writebuf, txstate.index) == COM_OK)
517   {
518     nwritten = txstate.index;
519     if (pfnProgressCallback != NULL)
520     {
521       progressInfo.nWritten += nwritten;
522       (*pfnProgressCallback)(&progressInfo);
523     }
524   }
525   else
526   {
527       MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP);
528       return -1;   /* SJ - This really needs to return a value, which is picked up in */
529                    /*      DevSW_Read as meaning stop debugger but don't kill. */
530   }
531 #else
532     nwritten = Unix_WriteParallel(txstate.writebuf, txstate.index);
533 #endif
534 
535     if (nwritten < 0) nwritten = 0;
536 
537 #ifdef DO_TRACE
538     printf("SerparWrite: wrote %d out of %d bytes\n",
539            nwritten, txstate.index);
540 #endif
541 
542     /*
543      * has the whole packet gone?
544      */
545     if (nwritten == (int)txstate.index &&
546         (status == TS_DONE_PKT || status == TS_IDLE))
547         /*
548          * yes it has
549          */
550         return 1;
551     else
552     {
553         /*
554          * if some data are left, shuffle them
555          * to the start of the buffer
556          */
557         if (nwritten != (int)txstate.index && nwritten != 0)
558         {
559             txstate.index -= nwritten;
560             (void)memmove((char *) txstate.writebuf,
561                           (char *) (txstate.writebuf + nwritten),
562                           txstate.index);
563         }
564         else if (nwritten == (int)txstate.index)
565             txstate.index = 0;
566 
567         return 0;
568     }
569 }
570 
serpar_reset(void)571 static int serpar_reset(void)
572 {
573 #ifdef COMPILING_ON_WINDOWS
574     FlushParallel();
575     FlushSerial();
576 #else
577     Unix_ResetParallel();
578     Unix_ResetSerial();
579 #endif
580 
581     return serpar_set_params(&serpar_defaults);
582 }
583 
find_baud_rate(unsigned int * speed)584 static int find_baud_rate(unsigned int *speed)
585 {
586     static struct
587     {
588         unsigned int baud;
589         int termiosValue;
590     } possibleBaudRates[] =
591       {
592 #if defined(__hpux)
593           {115200, _B115200}, {57600, _B57600},
594 #endif
595 #ifdef COMPILING_ON_WINDOWS
596         {38400, CBR_38400}, {19200, CBR_19200}, {9600, CBR_9600}, {0, 0}
597 #else
598         {38400, B38400}, {19200, B19200}, {9600, B9600}, {0, 0}
599 #endif
600     };
601     unsigned int i;
602 
603     /* look for lower or matching -- will always terminate at 0 end marker */
604     for (i = 0; possibleBaudRates[i].baud > *speed; ++i)
605         /* do nothing */
606         ;
607 
608     if (possibleBaudRates[i].baud > 0)
609        *speed = possibleBaudRates[i].baud;
610 
611     return possibleBaudRates[i].termiosValue;
612 }
613 
serpar_set_params(const ParameterConfig * config)614 static int serpar_set_params(const ParameterConfig *config)
615 {
616     unsigned int speed;
617     int termios_value;
618 
619 #ifdef DEBUG
620     printf("serpar_set_params\n");
621 #endif
622 
623     if (!Angel_FindParam(AP_BAUD_RATE, config, &speed))
624     {
625 #ifdef DEBUG
626         printf("speed not found in config\n");
627 #endif
628         return DE_OKAY;
629     }
630 
631     termios_value = find_baud_rate(&speed);
632     if (termios_value == 0)
633     {
634 #ifdef DEBUG
635         printf("speed not valid: %u\n", speed);
636 #endif
637         return DE_OKAY;
638     }
639 
640 #ifdef DEBUG
641     printf("setting speed to %u\n", speed);
642 #endif
643 
644 #ifdef COMPILING_ON_WINDOWS
645     SetBaudRate((WORD)termios_value);
646 #else
647     Unix_SetSerialBaudRate(termios_value);
648 #endif
649 
650     return DE_OKAY;
651 }
652 
653 
serpar_get_user_params(ParameterOptions ** p_options)654 static int serpar_get_user_params(ParameterOptions **p_options)
655 {
656 #ifdef DEBUG
657     printf("serpar_get_user_params\n");
658 #endif
659 
660     if (user_options_set)
661     {
662         *p_options = &user_options;
663     }
664     else
665     {
666         *p_options = NULL;
667     }
668 
669     return DE_OKAY;
670 }
671 
672 
serial_get_default_params(const ParameterConfig ** p_config)673 static int serial_get_default_params( const ParameterConfig **p_config )
674 {
675 #ifdef DEBUG
676     printf( "serial_get_default_params\n" );
677 #endif
678 
679     *p_config = &serpar_defaults;
680     return DE_OKAY;
681 }
682 
683 
SerparIoctl(const int opcode,void * args)684 static int SerparIoctl(const int opcode, void *args)
685 {
686     int ret_code;
687 
688 #ifdef DEBUG
689     printf("SerparIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>");
690 #endif
691 
692     switch (opcode)
693     {
694        case DC_RESET:
695            ret_code = serpar_reset();
696            break;
697 
698        case DC_SET_PARAMS:
699            ret_code = serpar_set_params((const ParameterConfig *)args);
700            break;
701 
702        case DC_GET_USER_PARAMS:
703            ret_code = serpar_get_user_params((ParameterOptions **)args);
704            break;
705 
706        case DC_GET_DEFAULT_PARAMS:
707            ret_code =
708                serial_get_default_params((const ParameterConfig **)args);
709            break;
710 
711        default:
712            ret_code = DE_BAD_OP;
713            break;
714     }
715 
716   return ret_code;
717 }
718 
719 DeviceDescr angel_SerparDevice =
720 {
721     "SERPAR",
722     SerparOpen,
723     SerparMatch,
724     SerparClose,
725     SerparRead,
726     SerparWrite,
727     SerparIoctl
728 };
729 
730 /* EOF serpardr.c */
731