2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
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
15 * serpardv.c - Serial/Parallel Driver for Angel.
30 #ifdef COMPILING_ON_WINDOWS
34 # include "angeldll.h"
35 # include "comb_api.h"
38 # define _TERMIOS_INCLUDED
39 # include <sys/termio.h>
40 # undef _TERMIOS_INCLUDED
44 # include "unixcomm.h"
48 # define UNUSED(x) (x = x) /* Silence compiler warnings */
51 #define MAXREADSIZE 512
52 #define MAXWRITESIZE 512
54 #define SERPAR_FC_SET ((1 << serial_XON) | (1 << serial_XOFF))
55 #define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \
57 #define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET)
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 */
68 static struct re_state rxstate
;
71 * structure used for manipulating transmit data
73 typedef struct TxState
75 struct te_state state
;
77 unsigned char writebuf
[MAXWRITESIZE
];
81 * The set of parameter options supported by the device
83 static unsigned int baud_options
[] =
91 static ParameterList param_list
[] =
95 sizeof(baud_options
) / sizeof(unsigned int),
100 static const ParameterOptions serpar_options
=
102 sizeof(param_list
) / sizeof(ParameterList
),
107 * The default parameter config for the device
109 static Parameter param_default
[] =
111 { AP_BAUD_RATE
, 9600 }
114 static const ParameterConfig serpar_defaults
=
116 sizeof(param_default
)/sizeof(Parameter
),
121 * The user-modified options for the device
123 static unsigned int user_baud_options
[sizeof(baud_options
) /
124 sizeof(unsigned int)];
126 static ParameterList param_user_list
[] =
130 sizeof(user_baud_options
) / sizeof(unsigned),
135 static ParameterOptions user_options
=
137 sizeof(param_user_list
) / sizeof(ParameterList
),
141 static bool user_options_set
;
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
);
148 static void process_baud_rate(unsigned int target_baud_rate
)
150 const ParameterList
*full_list
;
151 ParameterList
*user_list
;
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
);
157 if (full_list
!= NULL
&& user_list
!= NULL
)
160 unsigned int def_baud
= 0;
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
])
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
;
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
))
176 printf("user selected default\n");
181 user_options_set
= TRUE
;
183 printf("user options are: ");
184 for (j
= 0; j
< user_list
->num_options
; ++j
)
185 printf("%u ", user_list
->option
[j
]);
190 break; /* out of i loop */
194 if (i
>= full_list
->num_options
)
195 printf("couldn't match baud rate %u\n", target_baud_rate
);
200 printf("failed to find lists\n");
204 static int SerparOpen(const char *name
, const char *arg
)
206 char *sername
= NULL
;
207 char *parname
= NULL
;
210 printf("SerparOpen: name %s arg %s\n", name
, arg
? arg
: "<NULL>");
213 #ifdef COMPILING_ON_WINDOWS
214 if (IsOpenSerial() || IsOpenParallel()) return -1;
216 if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1;
219 #ifdef COMPILING_ON_WINDOWS
220 if (SerparMatch(name
, arg
) == -1)
223 Unix_IsValidParallelDevice(name
,&sername
,&parname
);
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
);
230 if (sername
==NULL
|| parname
==NULL
) return -1;
233 user_options_set
= FALSE
;
235 /* interpret and store the arguments */
238 unsigned int target_baud_rate
;
240 target_baud_rate
= (unsigned int)strtoul(arg
, NULL
, 10);
242 if (target_baud_rate
> 0)
245 printf("user selected baud rate %u\n", target_baud_rate
);
247 process_baud_rate(target_baud_rate
);
251 printf("could not understand baud rate %s\n", arg
);
255 #ifdef COMPILING_ON_WINDOWS
258 * The serial port number is in name[0] followed by
259 * the parallel port number in name[1]
262 int sport
= name
[0] - '0';
263 int pport
= name
[1] - '0';
265 if (OpenParallel(pport
) != COM_OK
)
268 if (OpenSerial(sport
, FALSE
) != COM_OK
)
275 Unix_OpenParallel(parname
);
276 Unix_OpenSerial(sername
);
281 #if defined(__unix) || defined(__CYGWIN32__)
282 Unix_ioctlNonBlocking();
285 Angel_RxEngineInit(&config
, &rxstate
);
290 #ifdef COMPILING_ON_WINDOWS
291 static int SerparMatch(const char *name
, const char *arg
)
298 sername
[0] = name
[0];
299 parname
[0] = name
[1];
300 sername
[1] = parname
[1] = 0;
302 if (IsValidDevice(sername
) == COM_DEVICENOTVALID
||
303 IsValidDevice(parname
) == COM_DEVICENOTVALID
)
309 static int SerparMatch(const char *portstring
, const char *arg
)
311 char *sername
=NULL
, *parname
=NULL
;
314 Unix_IsValidParallelDevice(portstring
,&sername
,&parname
);
316 /* Match failed if either sername or parname are still NULL */
317 if (sername
==NULL
|| parname
==NULL
) return -1;
322 static void SerparClose(void)
324 #ifdef COMPILING_ON_WINDOWS
328 Unix_CloseParallel();
333 static int SerparRead(DriverCall
*dc
, bool block
)
335 static unsigned char readbuf
[MAXREADSIZE
];
336 static int rbindex
= 0;
342 int ret_code
= -1; /* assume bad packet or error */
345 * we must not overflow buffer, and must start after
348 #ifdef COMPILING_ON_WINDOWS
351 nread
= BytesInRXBufferSerial();
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
)
358 progressInfo
.nRead
+= nread
;
359 (*pfnProgressCallback
)(&progressInfo
);
363 nread
= Unix_ReadSerial(readbuf
+rbindex
, MAXREADSIZE
-rbindex
, block
);
367 if ((nread
> 0) || (rbindex
> 0))
370 printf("[%d@%d] ", nread
, rbindex
);
374 rbindex
= rbindex
+ nread
;
378 restatus
= Angel_RxEngine(readbuf
[c
], &(dc
->dc_packet
), &rxstate
);
381 printf("<%02X ",readbuf
[c
]);
384 } while (c
< rbindex
&&
385 ((restatus
== RS_IN_PKT
) || (restatus
== RS_WAIT_PKT
)));
395 /* fall through to: */
399 * We now need to shuffle any left over data down to the
400 * beginning of our private buffer ready to be used
404 printf("SerparRead() processed %d, moving down %d\n",
409 memmove((char *) readbuf
, (char *) (readbuf
+ c
), rbindex
- c
);
417 rbindex
= 0; /* will have processed all we had */
423 printf("Bad re_status in SerparRead()\n");
429 /* nothing to read */
431 else if (read_errno
== ERRNO_FOR_BLOCKED_IO
) /* nread < 0 */
435 if ((nread
< 0) && (read_errno
!= ERRNO_FOR_BLOCKED_IO
))
436 perror("read() error in SerparRead()");
443 * Function: send_packet
444 * Purpose: Send a stream of bytes to Angel through the parallel port
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).
458 * Input: txstate Contains the packet to be sent
460 * Returns: Number of *complete* bytes written
463 static int SerparWrite(DriverCall
*dc
)
467 static TxState txstate
;
470 * is this a new packet?
472 if (dc
->dc_context
== NULL
)
475 * yes - initialise TxEngine
477 Angel_TxEngineInit(&config
, &dc
->dc_packet
, &txstate
.state
);
480 dc
->dc_context
= &txstate
;
484 * fill the buffer using the Tx Engine
488 status
= Angel_TxEngine(&dc
->dc_packet
, &txstate
.state
,
489 &txstate
.writebuf
[txstate
.index
]);
490 if (status
!= TS_IDLE
) txstate
.index
++;
492 } while (status
== TS_IN_PKT
&& txstate
.index
< MAXWRITESIZE
);
498 while (i
< txstate
.index
)
500 printf(">%02X ", txstate
.writebuf
[i
]);
512 * the data are ready, all we need now is to send them out
513 * in a form that Angel can swallow.
515 #ifdef COMPILING_ON_WINDOWS
516 if (WriteParallel(txstate
.writebuf
, txstate
.index
) == COM_OK
)
518 nwritten
= txstate
.index
;
519 if (pfnProgressCallback
!= NULL
)
521 progressInfo
.nWritten
+= nwritten
;
522 (*pfnProgressCallback
)(&progressInfo
);
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. */
532 nwritten
= Unix_WriteParallel(txstate
.writebuf
, txstate
.index
);
535 if (nwritten
< 0) nwritten
= 0;
538 printf("SerparWrite: wrote %d out of %d bytes\n",
539 nwritten
, txstate
.index
);
543 * has the whole packet gone?
545 if (nwritten
== (int)txstate
.index
&&
546 (status
== TS_DONE_PKT
|| status
== TS_IDLE
))
554 * if some data are left, shuffle them
555 * to the start of the buffer
557 if (nwritten
!= (int)txstate
.index
&& nwritten
!= 0)
559 txstate
.index
-= nwritten
;
560 (void)memmove((char *) txstate
.writebuf
,
561 (char *) (txstate
.writebuf
+ nwritten
),
564 else if (nwritten
== (int)txstate
.index
)
571 static int serpar_reset(void)
573 #ifdef COMPILING_ON_WINDOWS
577 Unix_ResetParallel();
581 return serpar_set_params(&serpar_defaults
);
584 static int find_baud_rate(unsigned int *speed
)
590 } possibleBaudRates
[] =
593 {115200, _B115200
}, {57600, _B57600
},
595 #ifdef COMPILING_ON_WINDOWS
596 {38400, CBR_38400
}, {19200, CBR_19200
}, {9600, CBR_9600
}, {0, 0}
598 {38400, B38400
}, {19200, B19200
}, {9600, B9600
}, {0, 0}
603 /* look for lower or matching -- will always terminate at 0 end marker */
604 for (i
= 0; possibleBaudRates
[i
].baud
> *speed
; ++i
)
608 if (possibleBaudRates
[i
].baud
> 0)
609 *speed
= possibleBaudRates
[i
].baud
;
611 return possibleBaudRates
[i
].termiosValue
;
614 static int serpar_set_params(const ParameterConfig
*config
)
620 printf("serpar_set_params\n");
623 if (!Angel_FindParam(AP_BAUD_RATE
, config
, &speed
))
626 printf("speed not found in config\n");
631 termios_value
= find_baud_rate(&speed
);
632 if (termios_value
== 0)
635 printf("speed not valid: %u\n", speed
);
641 printf("setting speed to %u\n", speed
);
644 #ifdef COMPILING_ON_WINDOWS
645 SetBaudRate((WORD
)termios_value
);
647 Unix_SetSerialBaudRate(termios_value
);
654 static int serpar_get_user_params(ParameterOptions
**p_options
)
657 printf("serpar_get_user_params\n");
660 if (user_options_set
)
662 *p_options
= &user_options
;
673 static int serial_get_default_params( const ParameterConfig
**p_config
)
676 printf( "serial_get_default_params\n" );
679 *p_config
= &serpar_defaults
;
684 static int SerparIoctl(const int opcode
, void *args
)
689 printf("SerparIoctl: op %d arg %p\n", opcode
, args
? args
: "<NULL>");
695 ret_code
= serpar_reset();
699 ret_code
= serpar_set_params((const ParameterConfig
*)args
);
702 case DC_GET_USER_PARAMS
:
703 ret_code
= serpar_get_user_params((ParameterOptions
**)args
);
706 case DC_GET_DEFAULT_PARAMS
:
708 serial_get_default_params((const ParameterConfig
**)args
);
712 ret_code
= DE_BAD_OP
;
719 DeviceDescr angel_SerparDevice
=