/[rdesktop]/jpeg/rdesktop/trunk/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

Annotation of /jpeg/rdesktop/trunk/serial.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 592 - (hide annotations)
Fri Jan 30 14:10:32 2004 UTC (20 years, 3 months ago) by n-ki
Original Path: sourceforge.net/trunk/rdesktop/serial.c
File MIME type: text/plain
File size: 13498 byte(s)
reworked the asyncio some and completed it. parallel and serial uses it now. disk.c is a likely candidate for the future, but there are some problems with disk.c that we will have to look into first. parallel and serial works better, they do not hang the session, but are still yerky at large chunks... possibly we could split the chunks, but the terminal server does not seem to like partial transfers, i've tried some variations.. :) fns->write() could be split in smaller pieces, but what should the thresholds be.

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

  ViewVC Help
Powered by ViewVC 1.1.26