/[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 569 - (show annotations)
Wed Jan 21 14:40:40 2004 UTC (20 years, 4 months ago) by n-ki
File MIME type: text/plain
File size: 15780 byte(s)
redirection of disk, lptport, printer, comport.

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

  ViewVC Help
Powered by ViewVC 1.1.26