Commit | Line | Data |
---|---|---|
3a9c3d12 NC |
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 | * 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 | ||
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 | ||
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(__CYGWIN32__) | |
282 | Unix_ioctlNonBlocking(); | |
283 | #endif | |
284 | ||
285 | Angel_RxEngineInit(&config, &rxstate); | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | #ifdef COMPILING_ON_WINDOWS | |
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 | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 */ |