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 * serdrv.c - Synchronous Serial Driver for Angel.
16 * This is nice and simple just to get something going.
20 # define _POSIX_SOURCE 1
35 #ifdef COMPILING_ON_WINDOWS
39 # include "angeldll.h"
40 # include "comb_api.h"
43 # define _TERMIOS_INCLUDED
44 # include <sys/termio.h>
45 # undef _TERMIOS_INCLUDED
49 # include "unixcomm.h"
53 # define UNUSED(x) (x = x) /* Silence compiler warnings */
56 #define MAXREADSIZE 512
57 #define MAXWRITESIZE 512
59 #define SERIAL_FC_SET ((1<<serial_XON)|(1<<serial_XOFF))
60 #define SERIAL_CTL_SET ((1<<serial_STX)|(1<<serial_ETX)|(1<<serial_ESC))
61 #define SERIAL_ESC_SET (SERIAL_FC_SET|SERIAL_CTL_SET)
63 static const struct re_config config
= {
64 serial_STX
, serial_ETX
, serial_ESC
, /* self-explanatory? */
65 SERIAL_FC_SET
, /* set of flow-control characters */
66 SERIAL_ESC_SET
, /* set of characters to be escaped */
67 NULL
/* serial_flow_control */, NULL
, /* what to do with FC chars */
68 angel_DD_RxEng_BufferAlloc
, NULL
/* how to get a buffer */
71 static struct re_state rxstate
;
73 typedef struct writestate
{
75 /* static te_status testatus;*/
76 unsigned char writebuf
[MAXWRITESIZE
];
77 struct te_state txstate
;
80 static struct writestate wstate
;
83 * The set of parameter options supported by the device
85 static unsigned int baud_options
[] = {
92 static ParameterList param_list
[] = {
94 sizeof(baud_options
)/sizeof(unsigned int),
98 static const ParameterOptions serial_options
= {
99 sizeof(param_list
)/sizeof(ParameterList
), param_list
};
102 * The default parameter config for the device
104 static Parameter param_default
[] = {
105 { AP_BAUD_RATE
, 9600 }
108 static ParameterConfig serial_defaults
= {
109 sizeof(param_default
)/sizeof(Parameter
), param_default
};
112 * The user-modified options for the device
114 static unsigned int user_baud_options
[sizeof(baud_options
)/sizeof(unsigned)];
116 static ParameterList param_user_list
[] = {
118 sizeof(user_baud_options
)/sizeof(unsigned),
122 static ParameterOptions user_options
= {
123 sizeof(param_user_list
)/sizeof(ParameterList
), param_user_list
};
125 static bool user_options_set
;
127 /* forward declarations */
128 static int serial_reset( void );
129 static int serial_set_params( const ParameterConfig
*config
);
130 static int SerialMatch(const char *name
, const char *arg
);
132 static void process_baud_rate( unsigned int target_baud_rate
)
134 const ParameterList
*full_list
;
135 ParameterList
*user_list
;
137 /* create subset of full options */
138 full_list
= Angel_FindParamList( &serial_options
, AP_BAUD_RATE
);
139 user_list
= Angel_FindParamList( &user_options
, AP_BAUD_RATE
);
141 if ( full_list
!= NULL
&& user_list
!= NULL
)
144 unsigned int def_baud
= 0;
146 /* find lower or equal to */
147 for ( i
= 0; i
< full_list
->num_options
; ++i
)
148 if ( target_baud_rate
>= full_list
->option
[i
] )
151 for ( j
= 0; j
< (full_list
->num_options
- i
); ++j
)
152 user_list
->option
[j
] = full_list
->option
[i
+j
];
153 user_list
->num_options
= j
;
155 /* check this is not the default */
156 Angel_FindParam( AP_BAUD_RATE
, &serial_defaults
, &def_baud
);
157 if ( (j
== 1) && (user_list
->option
[0] == def_baud
) )
160 printf( "user selected default\n" );
165 user_options_set
= TRUE
;
167 printf( "user options are: " );
168 for ( j
= 0; j
< user_list
->num_options
; ++j
)
169 printf( "%u ", user_list
->option
[j
] );
174 break; /* out of i loop */
178 if ( i
>= full_list
->num_options
)
179 printf( "couldn't match baud rate %u\n", target_baud_rate
);
184 printf( "failed to find lists\n" );
188 static int SerialOpen(const char *name
, const char *arg
)
190 const char *port_name
= name
;
193 printf("SerialOpen: name %s arg %s\n", name
, arg
? arg
: "<NULL>");
196 #ifdef COMPILING_ON_WINDOWS
197 if (IsOpenSerial()) return -1;
199 if (Unix_IsSerialInUse()) return -1;
202 #ifdef COMPILING_ON_WINDOWS
203 if (SerialMatch(name
, arg
) != adp_ok
)
206 port_name
= Unix_MatchValidSerialDevice(port_name
);
208 printf("translated port to %s\n", port_name
== 0 ? "NULL" : port_name
);
210 if (port_name
== 0) return adp_failed
;
213 user_options_set
= FALSE
;
215 /* interpret and store the arguments */
218 unsigned int target_baud_rate
;
219 target_baud_rate
= (unsigned int)strtoul(arg
, NULL
, 10);
220 if (target_baud_rate
> 0)
223 printf( "user selected baud rate %u\n", target_baud_rate
);
225 process_baud_rate( target_baud_rate
);
229 printf( "could not understand baud rate %s\n", arg
);
233 #ifdef COMPILING_ON_WINDOWS
235 int port
= IsValidDevice(name
);
236 if (OpenSerial(port
, FALSE
) != COM_OK
)
240 if (Unix_OpenSerial(port_name
) < 0)
246 #if defined(__unix) || defined(__CYGWIN32__)
247 Unix_ioctlNonBlocking();
250 Angel_RxEngineInit(&config
, &rxstate
);
252 * DANGER!: passing in NULL as the packet is ok for now as it is just
253 * IGNOREd but this may well change
255 Angel_TxEngineInit(&config
, NULL
, &wstate
.txstate
);
259 static int SerialMatch(const char *name
, const char *arg
)
262 #ifdef COMPILING_ON_WINDOWS
263 if (IsValidDevice(name
) == COM_DEVICENOTVALID
)
268 return Unix_MatchValidSerialDevice(name
) == 0 ? -1 : 0;
272 static void SerialClose(void)
275 printf("SerialClose()\n");
278 #ifdef COMPILING_ON_WINDOWS
285 static int SerialRead(DriverCall
*dc
, bool block
) {
286 static unsigned char readbuf
[MAXREADSIZE
];
287 static int rbindex
=0;
293 int ret_code
= -1; /* assume bad packet or error */
295 /* must not overflow buffer and must start after the existing data */
296 #ifdef COMPILING_ON_WINDOWS
299 nread
= BytesInRXBufferSerial();
301 if (nread
> MAXREADSIZE
- rbindex
)
302 nread
= MAXREADSIZE
- rbindex
;
304 if ((read_errno
= ReadSerial(readbuf
+rbindex
, nread
, &dummy
)) == COM_READFAIL
)
306 MessageBox(GetFocus(), "Read error\n", "Angel", MB_OK
| MB_ICONSTOP
);
307 return -1; /* SJ - This really needs to return a value, which is picked up in */
308 /* DevSW_Read as meaning stop debugger but don't kill. */
310 else if (pfnProgressCallback
!= NULL
&& read_errno
== COM_OK
)
312 progressInfo
.nRead
+= nread
;
313 (*pfnProgressCallback
)(&progressInfo
);
317 nread
= Unix_ReadSerial(readbuf
+rbindex
, MAXREADSIZE
-rbindex
, block
);
321 if ((nread
> 0) || (rbindex
> 0)) {
324 printf("[%d@%d] ", nread
, rbindex
);
328 rbindex
= rbindex
+nread
;
331 restatus
= Angel_RxEngine(readbuf
[c
], &(dc
->dc_packet
), &rxstate
);
333 printf("<%02X ",readbuf
[c
]);
339 } while (c
<rbindex
&&
340 ((restatus
== RS_IN_PKT
) || (restatus
== RS_WAIT_PKT
)));
351 /* fall through to: */
355 * We now need to shuffle any left over data down to the
356 * beginning of our private buffer ready to be used
360 printf("SerialRead() processed %d, moving down %d\n", c
, rbindex
-c
);
362 if (c
!= rbindex
) memmove((char *) readbuf
, (char *) (readbuf
+c
),
369 rbindex
= 0; /* will have processed all we had */
375 printf("Bad re_status in serialRead()\n");
379 } else if (nread
== 0)
380 ret_code
= 0; /* nothing to read */
381 else if (read_errno
== ERRNO_FOR_BLOCKED_IO
) /* nread < 0 */
385 if ((nread
<0) && (read_errno
!=ERRNO_FOR_BLOCKED_IO
))
386 perror("read() error in serialRead()");
393 static int SerialWrite(DriverCall
*dc
) {
395 te_status testatus
= TS_IN_PKT
;
397 if (dc
->dc_context
== NULL
) {
398 Angel_TxEngineInit(&config
, &(dc
->dc_packet
), &(wstate
.txstate
));
400 dc
->dc_context
= &wstate
;
403 while ((testatus
== TS_IN_PKT
) && (wstate
.wbindex
< MAXWRITESIZE
))
405 /* send the raw data through the tx engine to escape and encapsulate */
406 testatus
= Angel_TxEngine(&(dc
->dc_packet
), &(wstate
.txstate
),
407 &(wstate
.writebuf
)[wstate
.wbindex
]);
408 if (testatus
!= TS_IDLE
) wstate
.wbindex
++;
411 if (testatus
== TS_IDLE
) {
413 printf("SerialWrite: testatus is TS_IDLE during preprocessing\n");
421 while (i
<wstate
.wbindex
)
423 printf(">%02X ",wstate
.writebuf
[i
]);
433 #ifdef COMPILING_ON_WINDOWS
434 if (WriteSerial(wstate
.writebuf
, wstate
.wbindex
) == COM_OK
)
436 nwritten
= wstate
.wbindex
;
437 if (pfnProgressCallback
!= NULL
)
439 progressInfo
.nWritten
+= nwritten
;
440 (*pfnProgressCallback
)(&progressInfo
);
445 MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK
| MB_ICONSTOP
);
446 return -1; /* SJ - This really needs to return a value, which is picked up in */
447 /* DevSW_Read as meaning stop debugger but don't kill. */
450 nwritten
= Unix_WriteSerial(wstate
.writebuf
, wstate
.wbindex
);
459 printf("Wrote %#04x bytes\n", nwritten
);
462 if ((unsigned) nwritten
== wstate
.wbindex
&&
463 (testatus
== TS_DONE_PKT
|| testatus
== TS_IDLE
)) {
465 /* finished sending the packet */
468 printf("SerialWrite: calling Angel_TxEngineInit after sending packet (len=%i)\n",wstate
.wbindex
);
470 testatus
= TS_IN_PKT
;
476 printf("SerialWrite: Wrote part of packet wbindex=%i, nwritten=%i\n",
477 wstate
.wbindex
, nwritten
);
481 * still some data left to send shuffle whats left down and reset
484 memmove((char *) wstate
.writebuf
, (char *) (wstate
.writebuf
+nwritten
),
485 wstate
.wbindex
-nwritten
);
486 wstate
.wbindex
-= nwritten
;
493 static int serial_reset( void )
496 printf( "serial_reset\n" );
499 #ifdef COMPILING_ON_WINDOWS
505 return serial_set_params( &serial_defaults
);
509 static int find_baud_rate( unsigned int *speed
)
514 } possibleBaudRates
[] = {
516 {115200,_B115200
}, {57600,_B57600
},
518 #ifdef COMPILING_ON_WINDOWS
519 {38400,CBR_38400
}, {19200,CBR_19200
}, {9600, CBR_9600
}, {0,0}
521 {38400,B38400
}, {19200,B19200
}, {9600, B9600
}, {0,0}
526 /* look for lower or matching -- will always terminate at 0 end marker */
527 for ( i
= 0; possibleBaudRates
[i
].baud
> *speed
; ++i
)
530 if ( possibleBaudRates
[i
].baud
> 0 )
531 *speed
= possibleBaudRates
[i
].baud
;
533 return possibleBaudRates
[i
].termiosValue
;
537 static int serial_set_params( const ParameterConfig
*config
)
543 printf( "serial_set_params\n" );
546 if ( ! Angel_FindParam( AP_BAUD_RATE
, config
, &speed
) )
549 printf( "speed not found in config\n" );
554 termios_value
= find_baud_rate( &speed
);
555 if ( termios_value
== 0 )
558 printf( "speed not valid: %u\n", speed
);
564 printf( "setting speed to %u\n", speed
);
567 #ifdef COMPILING_ON_WINDOWS
568 SetBaudRate((WORD
)termios_value
);
570 Unix_SetSerialBaudRate(termios_value
);
577 static int serial_get_user_params( ParameterOptions
**p_options
)
580 printf( "serial_get_user_params\n" );
583 if ( user_options_set
)
585 *p_options
= &user_options
;
596 static int serial_get_default_params( ParameterConfig
**p_config
)
599 printf( "serial_get_default_params\n" );
602 *p_config
= (ParameterConfig
*) &serial_defaults
;
607 static int SerialIoctl(const int opcode
, void *args
) {
612 printf( "SerialIoctl: op %d arg %p\n", opcode
, args
? args
: "<NULL>");
618 ret_code
= serial_reset();
622 ret_code
= serial_set_params((const ParameterConfig
*)args
);
625 case DC_GET_USER_PARAMS
:
626 ret_code
= serial_get_user_params((ParameterOptions
**)args
);
629 case DC_GET_DEFAULT_PARAMS
:
630 ret_code
= serial_get_default_params((ParameterConfig
**)args
);
634 ret_code
= DE_BAD_OP
;
641 DeviceDescr angel_SerialDevice
= {