/[rdesktop]/sourceforge.net/trunk/rdesktop/serial.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/serial.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 570 - (show annotations)
Wed Jan 21 18:02:38 2004 UTC (20 years, 4 months ago) by stargo
File MIME type: text/plain
File size: 15805 byte(s)
some fixes for solaris compiles.
toupper was redefined to handle strings, now renamed to toupper_str
disk.c has some more problems (it uses statfs and dirfd)

1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <termios.h>
4 #include <strings.h>
5 #include "rdesktop.h"
6
7 #define FILE_DEVICE_SERIAL_PORT 0x1b
8
9 #define SERIAL_SET_BAUD_RATE 1
10 #define SERIAL_SET_QUEUE_SIZE 2
11 #define SERIAL_SET_LINE_CONTROL 3
12 #define SERIAL_SET_BREAK_ON 4
13 #define SERIAL_SET_BREAK_OFF 5
14 #define SERIAL_IMMEDIATE_CHAR 6
15 #define SERIAL_SET_TIMEOUTS 7
16 #define SERIAL_GET_TIMEOUTS 8
17 #define SERIAL_SET_DTR 9
18 #define SERIAL_CLR_DTR 10
19 #define SERIAL_RESET_DEVICE 11
20 #define SERIAL_SET_RTS 12
21 #define SERIAL_CLR_RTS 13
22 #define SERIAL_SET_XOFF 14
23 #define SERIAL_SET_XON 15
24 #define SERIAL_GET_WAIT_MASK 16
25 #define SERIAL_SET_WAIT_MASK 17
26 #define SERIAL_WAIT_ON_MASK 18
27 #define SERIAL_PURGE 19
28 #define SERIAL_GET_BAUD_RATE 20
29 #define SERIAL_GET_LINE_CONTROL 21
30 #define SERIAL_GET_CHARS 22
31 #define SERIAL_SET_CHARS 23
32 #define SERIAL_GET_HANDFLOW 24
33 #define SERIAL_SET_HANDFLOW 25
34 #define SERIAL_GET_MODEMSTATUS 26
35 #define SERIAL_GET_COMMSTATUS 27
36 #define SERIAL_XOFF_COUNTER 28
37 #define SERIAL_GET_PROPERTIES 29
38 #define SERIAL_GET_DTRRTS 30
39 #define SERIAL_LSRMST_INSERT 31
40 #define SERIAL_CONFIG_SIZE 32
41 #define SERIAL_GET_COMMCONFIG 33
42 #define SERIAL_SET_COMMCONFIG 34
43 #define SERIAL_GET_STATS 35
44 #define SERIAL_CLEAR_STATS 36
45 #define SERIAL_GET_MODEM_CONTROL 37
46 #define SERIAL_SET_MODEM_CONTROL 38
47 #define SERIAL_SET_FIFO_CONTROL 39
48
49 #define STOP_BITS_1 0
50 #define STOP_BITS_2 2
51
52 #define NO_PARITY 0
53 #define ODD_PARITY 1
54 #define EVEN_PARITY 2
55
56 extern RDPDR_DEVICE g_rdpdr_device[];
57
58 int serial_fd;
59 struct termios termios;
60
61 int dtr;
62 uint32 baud_rate;
63 uint32 queue_in_size, queue_out_size;
64 uint32 wait_mask;
65 uint8 stop_bits, parity, word_length;
66
67 SERIAL_DEVICE
68 *get_serial_info(HANDLE handle)
69 {
70 int index;
71
72 for (index = 0; index < RDPDR_MAX_DEVICES; index++)
73 {
74 if (handle == g_rdpdr_device[index].handle)
75 return (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data;
76 }
77 return NULL;
78 }
79
80 BOOL
81 get_termios(SERIAL_DEVICE *pser_inf, HANDLE serial_fd)
82 {
83 speed_t speed;
84 struct termios *ptermios;
85
86 ptermios = pser_inf->ptermios;
87
88 if (tcgetattr(serial_fd, ptermios) == -1)
89 return False;
90
91 speed = cfgetispeed(ptermios);
92 switch (speed)
93 {
94 #ifdef B75
95 case B75: pser_inf->baud_rate = 75; break;
96 #endif
97 #ifdef B110
98 case B110: pser_inf->baud_rate = 110; break;
99 #endif
100 #ifdef B134
101 case B134: pser_inf->baud_rate = 134; break;
102 #endif
103 #ifdef B150
104 case B150: pser_inf->baud_rate = 150; break;
105 #endif
106 #ifdef B300
107 case B300: pser_inf->baud_rate = 300; break;
108 #endif
109 #ifdef B600
110 case B600: pser_inf->baud_rate = 600; break;
111 #endif
112 #ifdef B1200
113 case B1200: pser_inf->baud_rate = 1200; break;
114 #endif
115 #ifdef B1800
116 case B1800: pser_inf->baud_rate = 1800; break;
117 #endif
118 #ifdef B2400
119 case B2400: pser_inf->baud_rate = 2400; break;
120 #endif
121 #ifdef B4800
122 case B4800: pser_inf->baud_rate = 4800; break;
123 #endif
124 #ifdef B9600
125 case B9600: pser_inf->baud_rate = 9600; break;
126 #endif
127 #ifdef B19200
128 case B19200: pser_inf->baud_rate = 19200; break;
129 #endif
130 #ifdef B38400
131 case B38400: pser_inf->baud_rate = 38400; break;
132 #endif
133 #ifdef B57600
134 case B57600: pser_inf->baud_rate = 57600; break;
135 #endif
136 #ifdef B115200
137 case B115200: pser_inf->baud_rate = 115200; break;
138 #endif
139 default: pser_inf->baud_rate = 0; break;
140 }
141
142 speed = cfgetospeed(ptermios);
143 pser_inf->dtr = (speed == B0) ? 0 : 1;
144
145 pser_inf->stop_bits = (ptermios->c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1;
146 pser_inf->parity = (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY;
147 switch (ptermios->c_cflag & CSIZE)
148 {
149 case CS5: pser_inf->word_length = 5; break;
150 case CS6: pser_inf->word_length = 6; break;
151 case CS7: pser_inf->word_length = 7; break;
152 default: pser_inf->word_length = 8; break;
153 }
154
155 return True;
156 }
157
158 static void
159 set_termios(void)
160 {
161 speed_t speed;
162
163 switch (baud_rate)
164 {
165 #ifdef B75
166 case 75: speed = B75;break;
167 #endif
168 #ifdef B110
169 case 110: speed = B110;break;
170 #endif
171 #ifdef B134
172 case 134: speed = B134;break;
173 #endif
174 #ifdef B150
175 case 150: speed = B150;break;
176 #endif
177 #ifdef B300
178 case 300: speed = B300;break;
179 #endif
180 #ifdef B600
181 case 600: speed = B600;break;
182 #endif
183 #ifdef B1200
184 case 1200: speed = B1200;break;
185 #endif
186 #ifdef B1800
187 case 1800: speed = B1800;break;
188 #endif
189 #ifdef B2400
190 case 2400: speed = B2400;break;
191 #endif
192 #ifdef B4800
193 case 4800: speed = B4800;break;
194 #endif
195 #ifdef B9600
196 case 9600: speed = B9600;break;
197 #endif
198 #ifdef B19200
199 case 19200: speed = B19200;break;
200 #endif
201 #ifdef B38400
202 case 38400: speed = B38400;break;
203 #endif
204 #ifdef B57600
205 case 57600: speed = B57600;break;
206 #endif
207 #ifdef B115200
208 case 115200: speed = B115200;break;
209 #endif
210 default: speed = B0;break;
211 }
212
213 /* on systems with separate ispeed and ospeed, we can remember the speed
214 in ispeed while changing DTR with ospeed */
215 cfsetispeed(&termios, speed);
216 cfsetospeed(&termios, dtr ? speed : 0);
217
218 termios.c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE);
219 switch (stop_bits)
220 {
221 case STOP_BITS_2:
222 termios.c_cflag |= CSTOPB;
223 break;
224 }
225 switch (parity)
226 {
227 case EVEN_PARITY:
228 termios.c_cflag |= PARENB;
229 break;
230 case ODD_PARITY:
231 termios.c_cflag |= PARENB | PARODD;
232 break;
233 }
234 switch (word_length)
235 {
236 case 5:
237 termios.c_cflag |= CS5;
238 break;
239 case 6:
240 termios.c_cflag |= CS6;
241 break;
242 case 7:
243 termios.c_cflag |= CS7;
244 break;
245 default:
246 termios.c_cflag |= CS8;
247 break;
248 }
249
250 tcsetattr(serial_fd, TCSANOW, &termios);
251 }
252
253 /* Enumeration of devices from rdesktop.c */
254 /* returns numer of units found and initialized. */
255 /* optarg looks like ':com1=/dev/ttyS0' */
256 /* when it arrives to this function. */
257 /* windev u*dev baud, parity, stop bits, wordlength */
258 /* :com1=/dev/ttyS0:9600,0|1|2,0|2,5|6|7|8:dtr */
259 int
260 serial_enum_devices(int *id, char* optarg)
261 {
262 SERIAL_DEVICE* pser_inf;
263
264 int argcount=0;
265 char* pos = optarg;
266 char* pos2;
267 char* pos3;
268
269 if(*id<RDPDR_MAX_DEVICES){
270 // Init data structures for device
271 pser_inf = (SERIAL_DEVICE *) xmalloc(sizeof(SERIAL_DEVICE));
272 pser_inf->ptermios = (struct termios *) xmalloc(sizeof(struct termios));
273 pser_inf->pold_termios = (struct termios *) xmalloc(sizeof(struct termios));
274
275 // skip the first colon
276 optarg++;
277 while( (pos = next_arg( optarg, ':')) ){
278
279 switch(argcount){
280 /* com1=/dev/ttyS0 */
281 case 0:
282 pos2 = next_arg(optarg,'=');
283 if( !pos2 || *pos2 == (char)0x00 ){
284 error("-r comport arguments should look like: -r comport:com1=/dev/ttyS0\n");
285 return 0;
286 }
287 /* optarg = com1, pos2 = /dev/ttyS0 */
288 strcpy(g_rdpdr_device[*id].name,optarg);
289
290 toupper_str(g_rdpdr_device[*id].name);
291
292 g_rdpdr_device[*id].local_path = xmalloc( strlen(pos2) + 1 );
293 strcpy(g_rdpdr_device[*id].local_path,pos2);
294 break;
295 /* 9600,0|1|2,O|2,5|6|7|8 */
296 /* TODO: values should be set in serial_create()... ??? */
297 case 1:
298 pos2 = next_arg(optarg,',');
299 /*optarg=9600*/
300 pser_inf->baud_rate = atoi(optarg);
301 if( !pos2 || *pos2 == (char)0x00 )
302 break;
303 pos3 = next_arg(pos2,',');
304 /* pos2 = 0|1|2 */
305 pser_inf->parity = atoi(pos2);
306 /* pos3 = 0|2,5|6|7|8*/
307 pos2 = next_arg(pos3,',');
308 if( !pos3 || *pos3 == (char)0x00 )
309 break;
310 pser_inf->stop_bits = atoi(pos3);
311 /* pos2 = 5|6|7|8 */
312 if( !pos2 || *pos2 == (char)0x00 )
313 break;
314 pser_inf->word_length = atoi(pos2);
315 break;
316 default:
317 if( (*optarg != (char)0x00) && (strcmp( optarg, "dtr" ) == 0) ){
318 pser_inf->dtr = 1;
319 }
320 /* TODO: add more switches here, like xon, xoff. they will be separated by colon
321 if( (*optarg != (char)0x00) && (strcmp( optarg, "xon" ) == 0) ){
322 }
323 */
324 break;
325 }
326 argcount++;
327 optarg=pos;
328 }
329
330 printf("SERIAL %s to %s", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path );
331 if( pser_inf->baud_rate != 0 ){
332 printf(" with baud: %u, parity: %u, stop bits: %u word length: %u", pser_inf->baud_rate, pser_inf->parity, pser_inf->stop_bits, pser_inf->word_length );
333 if( pser_inf->dtr )
334 printf( " dtr set\n");
335 else
336 printf( "\n" );
337 }else
338 printf("\n");
339
340 // set device type
341 g_rdpdr_device[*id].device_type = DEVICE_TYPE_SERIAL;
342 g_rdpdr_device[*id].pdevice_data = (void *) pser_inf;
343 (*id)++;
344
345 return 1;
346 }
347 return 0;
348 }
349
350 NTSTATUS
351 serial_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags_and_attributes, char *filename, HANDLE *handle)
352 {
353 HANDLE serial_fd;
354 SERIAL_DEVICE *pser_inf;
355 struct termios *ptermios;
356 SERIAL_DEVICE tmp_inf;
357
358 pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[device_id].pdevice_data;
359 ptermios = pser_inf->ptermios;
360 serial_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY);
361
362 if (serial_fd == -1)
363 return STATUS_ACCESS_DENIED;
364
365 // before we clog the user inserted args store them locally
366 //
367 memcpy(&tmp_inf,pser_inf, sizeof(pser_inf) );
368
369 if (!get_termios(pser_inf, serial_fd))
370 return STATUS_ACCESS_DENIED;
371
372 // Store handle for later use
373 g_rdpdr_device[device_id].handle = serial_fd;
374 tcgetattr(serial_fd, pser_inf->pold_termios); // Backup original settings
375
376 // Initial configuration.
377 bzero(ptermios, sizeof(ptermios));
378 ptermios->c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
379 ptermios->c_iflag = IGNPAR;
380 ptermios->c_oflag = 0;
381 ptermios->c_lflag = 0; //non-canonical, no echo
382 ptermios->c_cc[VTIME] = 0;
383 tcsetattr(serial_fd, TCSANOW, ptermios);
384
385 // overload with user settings
386 // -- if there are any
387 if( tmp_inf.baud_rate != 0 ){
388 dtr = tmp_inf.dtr;
389 baud_rate = tmp_inf.baud_rate;
390 parity = tmp_inf.parity;
391 stop_bits = tmp_inf.stop_bits;
392 word_length = tmp_inf.word_length;
393 set_termios();
394 }
395
396 *handle = serial_fd;
397 return STATUS_SUCCESS;
398 }
399
400 static NTSTATUS
401 serial_close(HANDLE handle)
402 {
403 close(serial_fd);
404 return STATUS_SUCCESS;
405 }
406
407 NTSTATUS
408 serial_read(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result)
409 {
410 long timeout;
411 SERIAL_DEVICE *pser_inf;
412 struct termios *ptermios;
413
414 timeout = 0;
415 pser_inf = get_serial_info(handle);
416 ptermios = pser_inf->ptermios;
417
418 // Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
419 // with requested read size
420 if (pser_inf->read_total_timeout_multiplier | pser_inf->read_total_timeout_constant)
421 {
422 timeout = (pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant + 99) / 100;
423 }
424 else if (pser_inf->read_interval_timeout)
425 {
426 timeout = (pser_inf->read_interval_timeout * length + 99) / 100;
427 }
428
429 // If a timeout is set, do a blocking read, which times out after some time.
430 // It will make rdesktop less responsive, but it will improve serial performance, by not
431 // reading one character at a time.
432 if (timeout == 0)
433 {
434 ptermios->c_cc[VTIME] = 0;
435 ptermios->c_cc[VMIN] = 0;
436 }
437 else
438 {
439 ptermios->c_cc[VTIME] = timeout;
440 ptermios->c_cc[VMIN] = 1;
441 }
442 tcsetattr(handle, TCSANOW, ptermios);
443
444 *result = read(handle, data, length);
445 return STATUS_SUCCESS;
446 }
447
448 NTSTATUS
449 serial_write(HANDLE handle, uint8 *data, uint32 length, uint32 offset, uint32 *result)
450 {
451 *result = write(handle, data, length);
452 return STATUS_SUCCESS;
453 }
454
455 static NTSTATUS
456 serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out)
457 {
458 uint32 result;
459 uint8 immediate;
460
461 if ((request >> 16) != FILE_DEVICE_SERIAL_PORT)
462 return STATUS_INVALID_PARAMETER;
463
464 /* extract operation */
465 request >>= 2;
466 request &= 0xfff;
467
468 printf("SERIAL IOCTL %d\n", request);
469
470 switch (request)
471 {
472 case SERIAL_SET_BAUD_RATE:
473 in_uint32_le(in, baud_rate);
474 set_termios();
475 break;
476 case SERIAL_GET_BAUD_RATE:
477 out_uint32_le(out, baud_rate);
478 break;
479 case SERIAL_SET_QUEUE_SIZE:
480 in_uint32_le(in, queue_in_size);
481 in_uint32_le(in, queue_out_size);
482 break;
483 case SERIAL_SET_LINE_CONTROL:
484 in_uint8(in, stop_bits);
485 in_uint8(in, parity);
486 in_uint8(in, word_length);
487 set_termios();
488 break;
489 case SERIAL_GET_LINE_CONTROL:
490 out_uint8(out, stop_bits);
491 out_uint8(out, parity);
492 out_uint8(out, word_length);
493 break;
494 case SERIAL_IMMEDIATE_CHAR:
495 in_uint8(in, immediate);
496 serial_write(handle, &immediate, 1, 0, &result);
497 break;
498 case SERIAL_CONFIG_SIZE:
499 out_uint32_le(out, 0);
500 break;
501 case SERIAL_GET_CHARS:
502 out_uint8s(out, 6);
503 break;
504 case SERIAL_SET_CHARS:
505 in_uint8s(in, 6);
506 break;
507 case SERIAL_GET_HANDFLOW:
508 out_uint32_le(out, 0);
509 out_uint32_le(out, 3); /* Xon/Xoff */
510 out_uint32_le(out, 0);
511 out_uint32_le(out, 0);
512 break;
513 case SERIAL_SET_HANDFLOW:
514 in_uint8s(in, 16);
515 break;
516 case SERIAL_SET_TIMEOUTS:
517 in_uint8s(in, 20);
518 break;
519 case SERIAL_GET_TIMEOUTS:
520 out_uint8s(out, 20);
521 break;
522 case SERIAL_GET_WAIT_MASK:
523 out_uint32(out, wait_mask);
524 break;
525 case SERIAL_SET_WAIT_MASK:
526 in_uint32(in, wait_mask);
527 break;
528 case SERIAL_SET_DTR:
529 dtr = 1;
530 set_termios();
531 break;
532 case SERIAL_CLR_DTR:
533 dtr = 0;
534 set_termios();
535 break;
536 #if 0
537 case SERIAL_WAIT_ON_MASK:
538 /* XXX implement me */
539 break;
540 case SERIAL_SET_BREAK_ON:
541 tcsendbreak(serial_fd, 0);
542 break;
543 case SERIAL_PURGE:
544
545 printf("SERIAL_PURGE\n");
546 in_uint32(in, purge_mask);
547 if (purge_mask & 0x04) flush_mask |= TCOFLUSH;
548 if (purge_mask & 0x08) flush_mask |= TCIFLUSH;
549 if (flush_mask != 0) tcflush(handle, flush_mask);
550 if (purge_mask & 0x01) rdpdr_abort_io(handle, 4, STATUS_CANCELLED);
551 if (purge_mask & 0x02) rdpdr_abort_io(handle, 3, STATUS_CANCELLED);
552 break;
553
554 case SERIAL_RESET_DEVICE:
555 case SERIAL_SET_BREAK_OFF:
556 case SERIAL_SET_RTS:
557 case SERIAL_CLR_RTS:
558 case SERIAL_SET_XOFF:
559 case SERIAL_SET_XON:
560 /* ignore */
561 break;
562 #endif
563
564 default:
565 unimpl("SERIAL IOCTL %d\n", request);
566 return STATUS_INVALID_PARAMETER;
567 }
568
569 return STATUS_SUCCESS;
570 }
571
572 /* Read timeout for a given file descripter (device) when adding fd's to select() */
573 BOOL
574 serial_get_timeout(uint32 handle, uint32 length, uint32 *timeout, uint32 *itv_timeout)
575 {
576 int index;
577 SERIAL_DEVICE *pser_inf;
578
579 index = get_device_index(handle);
580
581 if (g_rdpdr_device[index].device_type != DEVICE_TYPE_SERIAL)
582 {
583 return False;
584 }
585
586 pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data;
587
588 *timeout = pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant;
589 *itv_timeout = pser_inf->read_interval_timeout;
590 return True;
591 }
592
593 DEVICE_FNS serial_fns = {
594 serial_create,
595 serial_close,
596 serial_read,
597 serial_write,
598 serial_device_control
599 };

  ViewVC Help
Powered by ViewVC 1.1.26