]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
89d46774 | 2 | * "$Id: serial.c 5400 2006-04-14 19:04:02Z mike $" |
ef416fc2 | 3 | * |
4 | * Serial port backend for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. | |
7 | * | |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
18 | * Hollywood, Maryland 20636 USA | |
19 | * | |
20 | * Voice: (301) 373-9600 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * This file is subject to the Apple OS-Developed Software exception. | |
25 | * | |
26 | * Contents: | |
27 | * | |
28 | * main() - Send a file to the printer or server. | |
29 | * list_devices() - List all serial devices. | |
30 | */ | |
31 | ||
32 | /* | |
33 | * Include necessary headers. | |
34 | */ | |
35 | ||
36 | #include <cups/backend.h> | |
37 | #include <cups/cups.h> | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <errno.h> | |
41 | #include <cups/string.h> | |
42 | #include <signal.h> | |
43 | ||
44 | #ifdef __hpux | |
45 | # include <sys/modem.h> | |
46 | #endif /* __hpux */ | |
47 | ||
48 | #ifdef WIN32 | |
49 | # include <io.h> | |
50 | #else | |
51 | # include <unistd.h> | |
52 | # include <fcntl.h> | |
53 | # include <termios.h> | |
b423cd4c | 54 | # ifdef __hpux |
55 | # include <sys/time.h> | |
56 | # else | |
57 | # include <sys/select.h> | |
58 | # endif /* __hpux */ | |
ef416fc2 | 59 | # ifdef HAVE_SYS_IOCTL_H |
60 | # include <sys/ioctl.h> | |
61 | # endif /* HAVE_SYS_IOCTL_H */ | |
62 | #endif /* WIN32 */ | |
63 | ||
64 | #ifdef __sgi | |
65 | # include <invent.h> | |
66 | # ifndef INV_EPP_ECP_PLP | |
67 | # define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ | |
68 | # define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ | |
69 | # define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ | |
70 | # define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ | |
71 | # define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ | |
72 | # endif /* !INV_EPP_ECP_PLP */ | |
73 | #endif /* __sgi */ | |
74 | ||
75 | #ifndef CRTSCTS | |
76 | # ifdef CNEW_RTSCTS | |
77 | # define CRTSCTS CNEW_RTSCTS | |
78 | # else | |
79 | # define CRTSCTS 0 | |
80 | # endif /* CNEW_RTSCTS */ | |
81 | #endif /* !CRTSCTS */ | |
82 | ||
83 | #if defined(__APPLE__) | |
84 | # include <CoreFoundation/CoreFoundation.h> | |
85 | # include <IOKit/IOKitLib.h> | |
86 | # include <IOKit/serial/IOSerialKeys.h> | |
87 | # include <IOKit/IOBSD.h> | |
88 | #endif /* __APPLE__ */ | |
89 | ||
89d46774 | 90 | #if defined(__linux) && defined(TIOCGSERIAL) |
91 | # include <linux/serial.h> | |
92 | # include <linux/ioctl.h> | |
93 | #endif /* __linux && TIOCGSERIAL */ | |
94 | ||
ef416fc2 | 95 | |
96 | /* | |
97 | * Local functions... | |
98 | */ | |
99 | ||
100 | void list_devices(void); | |
101 | ||
102 | ||
103 | /* | |
104 | * 'main()' - Send a file to the printer or server. | |
105 | * | |
106 | * Usage: | |
107 | * | |
108 | * printer-uri job-id user title copies options [file] | |
109 | */ | |
110 | ||
111 | int /* O - Exit status */ | |
112 | main(int argc, /* I - Number of command-line arguments (6 or 7) */ | |
113 | char *argv[]) /* I - Command-line arguments */ | |
114 | { | |
115 | char method[255], /* Method in URI */ | |
116 | hostname[1024], /* Hostname */ | |
117 | username[255], /* Username info (not used) */ | |
118 | resource[1024], /* Resource info (device and options) */ | |
119 | *options, /* Pointer to options */ | |
120 | name[255], /* Name of option */ | |
121 | value[255], /* Value of option */ | |
122 | *ptr; /* Pointer into name or value */ | |
123 | int port; /* Port number (not used) */ | |
124 | int fp; /* Print file */ | |
125 | int copies; /* Number of copies to print */ | |
126 | int fd; /* Parallel device */ | |
127 | int rbytes; /* Number of bytes read */ | |
128 | int wbytes; /* Number of bytes written */ | |
129 | size_t nbytes, /* Number of bytes read */ | |
130 | tbytes; /* Total number of bytes written */ | |
131 | int dtrdsr; /* Do dtr/dsr flow control? */ | |
132 | int bufsize; /* Size of output buffer for writes */ | |
133 | char buffer[8192], /* Output buffer */ | |
134 | *bufptr; /* Pointer into buffer */ | |
135 | struct termios opts; /* Serial port options */ | |
136 | struct termios origopts; /* Original port options */ | |
137 | fd_set input, /* Input set for select() */ | |
138 | output; /* Output set for select() */ | |
139 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
140 | struct sigaction action; /* Actions for POSIX signals */ | |
141 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
142 | ||
143 | ||
144 | /* | |
145 | * Make sure status messages are not buffered... | |
146 | */ | |
147 | ||
148 | setbuf(stderr, NULL); | |
149 | ||
150 | /* | |
151 | * Ignore SIGPIPE signals... | |
152 | */ | |
153 | ||
154 | #ifdef HAVE_SIGSET | |
155 | sigset(SIGPIPE, SIG_IGN); | |
156 | #elif defined(HAVE_SIGACTION) | |
157 | memset(&action, 0, sizeof(action)); | |
158 | action.sa_handler = SIG_IGN; | |
159 | sigaction(SIGPIPE, &action, NULL); | |
160 | #else | |
161 | signal(SIGPIPE, SIG_IGN); | |
162 | #endif /* HAVE_SIGSET */ | |
163 | ||
164 | /* | |
165 | * Check command-line... | |
166 | */ | |
167 | ||
168 | if (argc == 1) | |
169 | { | |
170 | list_devices(); | |
171 | return (CUPS_BACKEND_OK); | |
172 | } | |
173 | else if (argc < 6 || argc > 7) | |
174 | { | |
175 | fputs("Usage: serial job-id user title copies options [file]\n", stderr); | |
176 | return (CUPS_BACKEND_FAILED); | |
177 | } | |
178 | ||
179 | /* | |
180 | * If we have 7 arguments, print the file named on the command-line. | |
181 | * Otherwise, send stdin instead... | |
182 | */ | |
183 | ||
184 | if (argc == 6) | |
185 | { | |
186 | fp = 0; | |
187 | copies = 1; | |
188 | } | |
189 | else | |
190 | { | |
191 | /* | |
192 | * Try to open the print file... | |
193 | */ | |
194 | ||
195 | if ((fp = open(argv[6], O_RDONLY)) < 0) | |
196 | { | |
197 | perror("ERROR: unable to open print file"); | |
198 | return (CUPS_BACKEND_FAILED); | |
199 | } | |
200 | ||
201 | copies = atoi(argv[4]); | |
202 | } | |
203 | ||
204 | /* | |
205 | * Extract the device name and options from the URI... | |
206 | */ | |
207 | ||
a4d04587 | 208 | httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), |
209 | method, sizeof(method), username, sizeof(username), | |
210 | hostname, sizeof(hostname), &port, | |
ef416fc2 | 211 | resource, sizeof(resource)); |
212 | ||
213 | /* | |
214 | * See if there are any options... | |
215 | */ | |
216 | ||
217 | if ((options = strchr(resource, '?')) != NULL) | |
218 | { | |
219 | /* | |
220 | * Yup, terminate the device name string and move to the first | |
221 | * character of the options... | |
222 | */ | |
223 | ||
224 | *options++ = '\0'; | |
225 | } | |
226 | ||
227 | /* | |
228 | * Open the serial port device... | |
229 | */ | |
230 | ||
757d2cad | 231 | fputs("STATE: +connecting-to-device\n", stderr); |
232 | ||
ef416fc2 | 233 | do |
234 | { | |
235 | if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL | O_NDELAY)) == -1) | |
236 | { | |
237 | if (getenv("CLASS") != NULL) | |
238 | { | |
239 | /* | |
240 | * If the CLASS environment variable is set, the job was submitted | |
241 | * to a class and not to a specific queue. In this case, we want | |
242 | * to abort immediately so that the job can be requeued on the next | |
243 | * available printer in the class. | |
244 | */ | |
245 | ||
246 | fputs("INFO: Unable to open serial port, queuing on next printer in class...\n", | |
247 | stderr); | |
248 | ||
249 | /* | |
250 | * Sleep 5 seconds to keep the job from requeuing too rapidly... | |
251 | */ | |
252 | ||
253 | sleep(5); | |
254 | ||
255 | return (CUPS_BACKEND_FAILED); | |
256 | } | |
257 | ||
258 | if (errno == EBUSY) | |
259 | { | |
260 | fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr); | |
261 | sleep(30); | |
262 | } | |
263 | else | |
264 | { | |
265 | fprintf(stderr, "ERROR: Unable to open serial port device file \"%s\": %s\n", | |
266 | resource, strerror(errno)); | |
267 | return (CUPS_BACKEND_FAILED); | |
268 | } | |
269 | } | |
270 | } | |
271 | while (fd < 0); | |
272 | ||
757d2cad | 273 | fputs("STATE: -connecting-to-device\n", stderr); |
274 | ||
ef416fc2 | 275 | /* |
276 | * Set any options provided... | |
277 | */ | |
278 | ||
279 | tcgetattr(fd, &origopts); | |
280 | tcgetattr(fd, &opts); | |
281 | ||
282 | opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ | |
283 | opts.c_oflag &= ~OPOST; /* Don't post-process */ | |
284 | ||
285 | bufsize = 96; /* 9600 baud / 10 bits/char / 10Hz */ | |
286 | dtrdsr = 0; /* No dtr/dsr flow control */ | |
287 | ||
288 | if (options != NULL) | |
289 | while (*options) | |
290 | { | |
291 | /* | |
292 | * Get the name... | |
293 | */ | |
294 | ||
295 | for (ptr = name; *options && *options != '=';) | |
296 | if (ptr < (name + sizeof(name) - 1)) | |
297 | *ptr++ = *options++; | |
298 | *ptr = '\0'; | |
299 | ||
300 | if (*options == '=') | |
301 | { | |
302 | /* | |
303 | * Get the value... | |
304 | */ | |
305 | ||
306 | options ++; | |
307 | ||
308 | for (ptr = value; *options && *options != '+' && *options != '&';) | |
309 | if (ptr < (value + sizeof(value) - 1)) | |
310 | *ptr++ = *options++; | |
311 | *ptr = '\0'; | |
312 | ||
313 | if (*options == '+') | |
314 | options ++; | |
315 | } | |
316 | else | |
317 | value[0] = '\0'; | |
318 | ||
319 | /* | |
320 | * Process the option... | |
321 | */ | |
322 | ||
323 | if (!strcasecmp(name, "baud")) | |
324 | { | |
325 | /* | |
326 | * Set the baud rate... | |
327 | */ | |
328 | ||
329 | bufsize = atoi(value) / 100; | |
330 | ||
331 | #if B19200 == 19200 | |
332 | cfsetispeed(&opts, atoi(value)); | |
333 | cfsetospeed(&opts, atoi(value)); | |
334 | #else | |
335 | switch (atoi(value)) | |
336 | { | |
337 | case 1200 : | |
338 | cfsetispeed(&opts, B1200); | |
339 | cfsetospeed(&opts, B1200); | |
340 | break; | |
341 | case 2400 : | |
342 | cfsetispeed(&opts, B2400); | |
343 | cfsetospeed(&opts, B2400); | |
344 | break; | |
345 | case 4800 : | |
346 | cfsetispeed(&opts, B4800); | |
347 | cfsetospeed(&opts, B4800); | |
348 | break; | |
349 | case 9600 : | |
350 | cfsetispeed(&opts, B9600); | |
351 | cfsetospeed(&opts, B9600); | |
352 | break; | |
353 | case 19200 : | |
354 | cfsetispeed(&opts, B19200); | |
355 | cfsetospeed(&opts, B19200); | |
356 | break; | |
357 | case 38400 : | |
358 | cfsetispeed(&opts, B38400); | |
359 | cfsetospeed(&opts, B38400); | |
360 | break; | |
361 | # ifdef B57600 | |
362 | case 57600 : | |
363 | cfsetispeed(&opts, B57600); | |
364 | cfsetospeed(&opts, B57600); | |
365 | break; | |
366 | # endif /* B57600 */ | |
367 | # ifdef B115200 | |
368 | case 115200 : | |
369 | cfsetispeed(&opts, B115200); | |
370 | cfsetospeed(&opts, B115200); | |
371 | break; | |
372 | # endif /* B115200 */ | |
373 | # ifdef B230400 | |
374 | case 230400 : | |
375 | cfsetispeed(&opts, B230400); | |
376 | cfsetospeed(&opts, B230400); | |
377 | break; | |
378 | # endif /* B230400 */ | |
379 | default : | |
380 | fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value); | |
381 | break; | |
382 | } | |
383 | #endif /* B19200 == 19200 */ | |
384 | } | |
385 | else if (!strcasecmp(name, "bits")) | |
386 | { | |
387 | /* | |
388 | * Set number of data bits... | |
389 | */ | |
390 | ||
391 | switch (atoi(value)) | |
392 | { | |
393 | case 7 : | |
394 | opts.c_cflag &= ~CSIZE; | |
395 | opts.c_cflag |= CS7; | |
396 | opts.c_cflag |= PARENB; | |
397 | opts.c_cflag &= ~PARODD; | |
398 | break; | |
399 | case 8 : | |
400 | opts.c_cflag &= ~CSIZE; | |
401 | opts.c_cflag |= CS8; | |
402 | opts.c_cflag &= ~PARENB; | |
403 | break; | |
404 | } | |
405 | } | |
406 | else if (!strcasecmp(name, "parity")) | |
407 | { | |
408 | /* | |
409 | * Set parity checking... | |
410 | */ | |
411 | ||
412 | if (!strcasecmp(value, "even")) | |
413 | { | |
414 | opts.c_cflag |= PARENB; | |
415 | opts.c_cflag &= ~PARODD; | |
416 | } | |
417 | else if (!strcasecmp(value, "odd")) | |
418 | { | |
419 | opts.c_cflag |= PARENB; | |
420 | opts.c_cflag |= PARODD; | |
421 | } | |
422 | else if (!strcasecmp(value, "none")) | |
423 | opts.c_cflag &= ~PARENB; | |
424 | else if (!strcasecmp(value, "space")) | |
425 | { | |
426 | /* | |
427 | * Note: we only support space parity with 7 bits per character... | |
428 | */ | |
429 | ||
430 | opts.c_cflag &= ~CSIZE; | |
431 | opts.c_cflag |= CS8; | |
432 | opts.c_cflag &= ~PARENB; | |
433 | } | |
434 | else if (!strcasecmp(value, "mark")) | |
435 | { | |
436 | /* | |
437 | * Note: we only support mark parity with 7 bits per character | |
438 | * and 1 stop bit... | |
439 | */ | |
440 | ||
441 | opts.c_cflag &= ~CSIZE; | |
442 | opts.c_cflag |= CS7; | |
443 | opts.c_cflag &= ~PARENB; | |
444 | opts.c_cflag |= CSTOPB; | |
445 | } | |
446 | } | |
447 | else if (!strcasecmp(name, "flow")) | |
448 | { | |
449 | /* | |
450 | * Set flow control... | |
451 | */ | |
452 | ||
453 | if (!strcasecmp(value, "none")) | |
454 | { | |
455 | opts.c_iflag &= ~(IXON | IXOFF); | |
456 | opts.c_cflag &= ~CRTSCTS; | |
457 | } | |
458 | else if (!strcasecmp(value, "soft")) | |
459 | { | |
460 | opts.c_iflag |= IXON | IXOFF; | |
461 | opts.c_cflag &= ~CRTSCTS; | |
462 | } | |
463 | else if (!strcasecmp(value, "hard") || | |
464 | !strcasecmp(value, "rtscts")) | |
465 | { | |
466 | opts.c_iflag &= ~(IXON | IXOFF); | |
467 | opts.c_cflag |= CRTSCTS; | |
468 | } | |
469 | else if (!strcasecmp(value, "dtrdsr")) | |
470 | { | |
471 | opts.c_iflag &= ~(IXON | IXOFF); | |
472 | opts.c_cflag &= ~CRTSCTS; | |
473 | ||
474 | dtrdsr = 1; | |
475 | } | |
476 | } | |
477 | else if (!strcasecmp(name, "stop")) | |
478 | { | |
479 | switch (atoi(value)) | |
480 | { | |
481 | case 1 : | |
482 | opts.c_cflag &= ~CSTOPB; | |
483 | break; | |
484 | ||
485 | case 2 : | |
486 | opts.c_cflag |= CSTOPB; | |
487 | break; | |
488 | } | |
489 | } | |
490 | } | |
491 | ||
492 | tcsetattr(fd, TCSANOW, &opts); | |
493 | fcntl(fd, F_SETFL, 0); | |
494 | ||
495 | /* | |
496 | * Now that we are "connected" to the port, ignore SIGTERM so that we | |
497 | * can finish out any page data the driver sends (e.g. to eject the | |
498 | * current page... Only ignore SIGTERM if we are printing data from | |
499 | * stdin (otherwise you can't cancel raw jobs...) | |
500 | */ | |
501 | ||
502 | if (argc < 7) | |
503 | { | |
504 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
505 | sigset(SIGTERM, SIG_IGN); | |
506 | #elif defined(HAVE_SIGACTION) | |
507 | memset(&action, 0, sizeof(action)); | |
508 | ||
509 | sigemptyset(&action.sa_mask); | |
510 | action.sa_handler = SIG_IGN; | |
511 | sigaction(SIGTERM, &action, NULL); | |
512 | #else | |
513 | signal(SIGTERM, SIG_IGN); | |
514 | #endif /* HAVE_SIGSET */ | |
515 | } | |
516 | ||
517 | /* | |
518 | * Finally, send the print file... | |
519 | */ | |
520 | ||
521 | if (bufsize > sizeof(buffer)) | |
522 | bufsize = sizeof(buffer); | |
523 | ||
524 | wbytes = 0; | |
525 | ||
526 | while (copies > 0) | |
527 | { | |
528 | copies --; | |
529 | ||
530 | if (fp != 0) | |
531 | { | |
532 | fputs("PAGE: 1 1\n", stderr); | |
533 | lseek(fp, 0, SEEK_SET); | |
534 | } | |
535 | ||
536 | if (dtrdsr) | |
537 | { | |
538 | /* | |
539 | * Check the port and sleep until DSR is set... | |
540 | */ | |
541 | ||
542 | int status; | |
543 | ||
544 | ||
545 | if (!ioctl(fd, TIOCMGET, &status)) | |
546 | if (!(status & TIOCM_DSR)) | |
547 | { | |
548 | /* | |
549 | * Wait for DSR to go high... | |
550 | */ | |
551 | ||
552 | fputs("DEBUG: DSR is low; waiting for device...\n", stderr); | |
553 | ||
554 | do | |
555 | { | |
556 | sleep(1); | |
557 | if (ioctl(fd, TIOCMGET, &status)) | |
558 | break; | |
559 | } | |
560 | while (!(status & TIOCM_DSR)); | |
561 | ||
562 | fputs("DEBUG: DSR is high; writing to device...\n", stderr); | |
563 | } | |
564 | } | |
565 | ||
566 | tbytes = 0; | |
567 | while ((nbytes = read(fp, buffer, bufsize)) > 0) | |
568 | { | |
569 | /* | |
570 | * Write the print data to the printer... | |
571 | */ | |
572 | ||
573 | tbytes += nbytes; | |
574 | bufptr = buffer; | |
575 | ||
576 | while (nbytes > 0) | |
577 | { | |
578 | /* | |
579 | * See if we are ready to read or write... | |
580 | */ | |
581 | ||
582 | do | |
583 | { | |
584 | FD_ZERO(&input); | |
585 | FD_SET(fd, &input); | |
586 | FD_ZERO(&output); | |
587 | FD_SET(fd, &output); | |
588 | } | |
589 | while (select(fd + 1, &input, &output, NULL, NULL) < 0); | |
590 | ||
591 | if (FD_ISSET(fd, &input)) | |
592 | { | |
593 | /* | |
594 | * Read backchannel data... | |
595 | */ | |
596 | ||
597 | if ((rbytes = read(fd, resource, sizeof(resource))) > 0) | |
598 | { | |
599 | fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", | |
600 | rbytes); | |
bd7854cb | 601 | cupsBackChannelWrite(resource, rbytes, 1.0); |
ef416fc2 | 602 | } |
603 | } | |
604 | ||
605 | if (FD_ISSET(fd, &output)) | |
606 | { | |
607 | /* | |
608 | * Write print data... | |
609 | */ | |
610 | ||
611 | if ((wbytes = write(fd, bufptr, nbytes)) < 0) | |
612 | if (errno == ENOTTY) | |
613 | wbytes = write(fd, bufptr, nbytes); | |
614 | ||
615 | if (wbytes < 0) | |
616 | { | |
617 | /* | |
618 | * Check for retryable errors... | |
619 | */ | |
620 | ||
621 | if (errno != EAGAIN && errno != EINTR) | |
622 | { | |
623 | perror("ERROR: Unable to send print file to printer"); | |
624 | break; | |
625 | } | |
626 | } | |
627 | else | |
628 | { | |
629 | /* | |
630 | * Update count and pointer... | |
631 | */ | |
632 | ||
633 | nbytes -= wbytes; | |
634 | bufptr += wbytes; | |
635 | } | |
636 | } | |
637 | } | |
638 | ||
639 | if (wbytes < 0) | |
640 | break; | |
641 | ||
642 | if (argc > 6) | |
643 | fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", | |
644 | (unsigned long)tbytes); | |
645 | } | |
646 | } | |
647 | ||
648 | /* | |
649 | * Close the serial port and input file and return... | |
650 | */ | |
651 | ||
652 | tcsetattr(fd, TCSADRAIN, &origopts); | |
653 | ||
654 | close(fd); | |
655 | if (fp != 0) | |
656 | close(fp); | |
657 | ||
658 | return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); | |
659 | } | |
660 | ||
661 | ||
662 | /* | |
663 | * 'list_devices()' - List all serial devices. | |
664 | */ | |
665 | ||
666 | void | |
667 | list_devices(void) | |
668 | { | |
b423cd4c | 669 | #if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) |
ef416fc2 | 670 | static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz"; |
89d46774 | 671 | /* Funky hex numbering used for some * |
672 | * devices */ | |
ef416fc2 | 673 | #endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ */ |
674 | ||
89d46774 | 675 | #ifdef __linux |
676 | int i, j; /* Looping vars */ | |
677 | int fd; /* File descriptor */ | |
678 | char device[255]; /* Device filename */ | |
679 | # ifdef TIOCGSERIAL | |
680 | struct serial_struct serinfo; /* serial port info */ | |
681 | # endif /* TIOCGSERIAL */ | |
ef416fc2 | 682 | |
683 | ||
684 | for (i = 0; i < 100; i ++) | |
685 | { | |
686 | sprintf(device, "/dev/ttyS%d", i); | |
89d46774 | 687 | |
ef416fc2 | 688 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) |
689 | { | |
89d46774 | 690 | # ifdef TIOCGSERIAL |
691 | /* | |
692 | * See if this port exists... | |
693 | */ | |
694 | ||
695 | serinfo.reserved_char[0] = 0; | |
696 | ||
697 | if (!ioctl(fd, TIOCGSERIAL, &serinfo)) | |
698 | { | |
699 | if (serinfo.type == PORT_UNKNOWN) | |
700 | { | |
701 | /* | |
702 | * Nope... | |
703 | */ | |
704 | ||
705 | close(fd); | |
706 | continue; | |
707 | } | |
708 | } | |
709 | # endif /* TIOCGSERIAL */ | |
710 | ||
ef416fc2 | 711 | close(fd); |
89d46774 | 712 | |
ef416fc2 | 713 | # if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc) |
714 | printf("serial serial:%s?baud=230400 \"Unknown\" \"Serial Port #%d\"\n", | |
715 | device, i + 1); | |
716 | # else | |
717 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", | |
718 | device, i + 1); | |
719 | # endif /* _ARCH_PPC || powerpc || __powerpc */ | |
720 | } | |
721 | } | |
722 | ||
723 | for (i = 0; i < 16; i ++) | |
724 | { | |
725 | sprintf(device, "/dev/usb/ttyUSB%d", i); | |
726 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
727 | { | |
728 | close(fd); | |
729 | printf("serial serial:%s?baud=230400 \"Unknown\" \"USB Serial Port #%d\"\n", | |
730 | device, i + 1); | |
731 | } | |
732 | } | |
b423cd4c | 733 | |
734 | for (i = 0; i < 64; i ++) | |
735 | { | |
736 | for (j = 0; j < 8; j ++) | |
737 | { | |
738 | sprintf(device, "/dev/ttyQ%02de%d", i, j); | |
739 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
740 | { | |
741 | close(fd); | |
742 | printf("serial serial:%s?baud=115200 \"Unknown\" " | |
743 | "\"Equinox ESP %d Port #%d\"\n", | |
744 | device, i, j + 1); | |
745 | } | |
746 | } | |
747 | } | |
ef416fc2 | 748 | #elif defined(__sgi) |
749 | int i, j, n; /* Looping vars */ | |
750 | char device[255]; /* Device filename */ | |
751 | inventory_t *inv; /* Hardware inventory info */ | |
752 | ||
753 | ||
754 | /* | |
755 | * IRIX maintains a hardware inventory of most devices... | |
756 | */ | |
757 | ||
758 | setinvent(); | |
759 | ||
760 | while ((inv = getinvent()) != NULL) | |
761 | { | |
762 | if (inv->inv_class == INV_SERIAL) | |
763 | { | |
764 | /* | |
765 | * Some sort of serial port... | |
766 | */ | |
767 | ||
768 | if (inv->inv_type == INV_CDSIO || inv->inv_type == INV_CDSIO_E) | |
769 | { | |
770 | /* | |
771 | * CDSIO port... | |
772 | */ | |
773 | ||
774 | for (n = 0; n < 6; n ++) | |
775 | printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"CDSIO Board %d Serial Port #%d\"\n", | |
776 | n + 5 + 8 * inv->inv_controller, inv->inv_controller, n + 1); | |
777 | } | |
778 | else if (inv->inv_type == INV_EPC_SERIAL) | |
779 | { | |
780 | /* | |
781 | * Everest serial port... | |
782 | */ | |
783 | ||
784 | if (inv->inv_unit == 0) | |
785 | i = 1; | |
786 | else | |
787 | i = 41 + 4 * (int)inv->inv_controller; | |
788 | ||
789 | for (n = 0; n < (int)inv->inv_state; n ++) | |
790 | printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"EPC Serial Port %d, Ebus slot %d\"\n", | |
791 | n + i, n + 1, (int)inv->inv_controller); | |
792 | } | |
793 | else if (inv->inv_state > 1) | |
794 | { | |
795 | /* | |
796 | * Standard serial port under IRIX 6.4 and earlier... | |
797 | */ | |
798 | ||
799 | for (n = 0; n < (int)inv->inv_state; n ++) | |
800 | printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"Onboard Serial Port %d\"\n", | |
801 | n + (int)inv->inv_unit + 1, n + (int)inv->inv_unit + 1); | |
802 | } | |
803 | else | |
804 | { | |
805 | /* | |
806 | * Standard serial port under IRIX 6.5 and beyond... | |
807 | */ | |
808 | ||
809 | printf("serial serial:/dev/ttyd%d?baud=115200 \"Unknown\" \"Onboard Serial Port %d\"\n", | |
810 | (int)inv->inv_controller, (int)inv->inv_controller); | |
811 | } | |
812 | } | |
813 | } | |
814 | ||
815 | endinvent(); | |
816 | ||
817 | /* | |
818 | * Central Data makes serial and parallel "servers" that can be | |
819 | * connected in a number of ways. Look for ports... | |
820 | */ | |
821 | ||
822 | for (i = 0; i < 10; i ++) | |
823 | for (j = 0; j < 8; j ++) | |
824 | for (n = 0; n < 32; n ++) | |
825 | { | |
826 | if (i == 8) /* EtherLite */ | |
827 | sprintf(device, "/dev/ttydn%d%c", j, funky_hex[n]); | |
828 | else if (i == 9) /* PCI */ | |
829 | sprintf(device, "/dev/ttydp%d%c", j, funky_hex[n]); | |
830 | else /* SCSI */ | |
831 | sprintf(device, "/dev/ttyd%d%d%c", i, j, funky_hex[n]); | |
832 | ||
833 | if (access(device, 0) == 0) | |
834 | { | |
835 | if (i == 8) | |
836 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", | |
837 | device, j, n); | |
838 | else if (i == 9) | |
839 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data PCI Serial Port, ID %d, port %d\"\n", | |
840 | device, j, n); | |
841 | else | |
842 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", | |
843 | device, i, j, n); | |
844 | } | |
845 | } | |
846 | #elif defined(__sun) | |
847 | int i, j, n; /* Looping vars */ | |
848 | char device[255]; /* Device filename */ | |
849 | ||
850 | ||
851 | /* | |
852 | * Standard serial ports... | |
853 | */ | |
854 | ||
855 | for (i = 0; i < 26; i ++) | |
856 | { | |
857 | sprintf(device, "/dev/cua/%c", 'a' + i); | |
858 | if (access(device, 0) == 0) | |
89d46774 | 859 | # ifdef B115200 |
ef416fc2 | 860 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", |
861 | device, i + 1); | |
89d46774 | 862 | # else |
ef416fc2 | 863 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", |
864 | device, i + 1); | |
89d46774 | 865 | # endif /* B115200 */ |
ef416fc2 | 866 | } |
867 | ||
868 | /* | |
869 | * MAGMA serial ports... | |
870 | */ | |
871 | ||
872 | for (i = 0; i < 40; i ++) | |
873 | { | |
874 | sprintf(device, "/dev/term/%02d", i); | |
875 | if (access(device, 0) == 0) | |
876 | printf("serial serial:%s?baud=38400 \"Unknown\" \"MAGMA Serial Board #%d Port #%d\"\n", | |
877 | device, (i / 10) + 1, (i % 10) + 1); | |
878 | } | |
879 | ||
880 | /* | |
881 | * Central Data serial ports... | |
882 | */ | |
883 | ||
884 | for (i = 0; i < 9; i ++) | |
885 | for (j = 0; j < 8; j ++) | |
886 | for (n = 0; n < 32; n ++) | |
887 | { | |
888 | if (i == 8) /* EtherLite */ | |
889 | sprintf(device, "/dev/sts/ttyN%d%c", j, funky_hex[n]); | |
890 | else | |
891 | sprintf(device, "/dev/sts/tty%c%d%c", i + 'C', j, | |
892 | funky_hex[n]); | |
893 | ||
894 | if (access(device, 0) == 0) | |
895 | { | |
896 | if (i == 8) | |
897 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", | |
898 | device, j, n); | |
899 | else | |
900 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", | |
901 | device, i, j, n); | |
902 | } | |
903 | } | |
904 | #elif defined(__hpux) | |
905 | int i, j, n; /* Looping vars */ | |
906 | char device[255]; /* Device filename */ | |
907 | ||
908 | ||
909 | /* | |
910 | * Standard serial ports... | |
911 | */ | |
912 | ||
913 | for (i = 0; i < 10; i ++) | |
914 | { | |
915 | sprintf(device, "/dev/tty%dp0", i); | |
916 | if (access(device, 0) == 0) | |
917 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", | |
918 | device, i + 1); | |
919 | } | |
920 | ||
921 | /* | |
922 | * Central Data serial ports... | |
923 | */ | |
924 | ||
925 | for (i = 0; i < 9; i ++) | |
926 | for (j = 0; j < 8; j ++) | |
927 | for (n = 0; n < 32; n ++) | |
928 | { | |
929 | if (i == 8) /* EtherLite */ | |
930 | sprintf(device, "/dev/ttyN%d%c", j, funky_hex[n]); | |
931 | else | |
932 | sprintf(device, "/dev/tty%c%d%c", i + 'C', j, | |
933 | funky_hex[n]); | |
934 | ||
935 | if (access(device, 0) == 0) | |
936 | { | |
937 | if (i == 8) | |
938 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", | |
939 | device, j, n); | |
940 | else | |
941 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", | |
942 | device, i, j, n); | |
943 | } | |
944 | } | |
945 | #elif defined(__osf__) | |
946 | int i; /* Looping var */ | |
947 | char device[255]; /* Device filename */ | |
948 | ||
949 | ||
950 | /* | |
951 | * Standard serial ports... | |
952 | */ | |
953 | ||
954 | for (i = 0; i < 100; i ++) | |
955 | { | |
956 | sprintf(device, "/dev/tty%02d", i); | |
957 | if (access(device, 0) == 0) | |
958 | printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", | |
959 | device, i + 1); | |
960 | } | |
b423cd4c | 961 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) |
ef416fc2 | 962 | int i, j; /* Looping vars */ |
963 | int fd; /* File descriptor */ | |
964 | char device[255]; /* Device filename */ | |
965 | ||
966 | ||
967 | /* | |
968 | * SIO ports... | |
969 | */ | |
970 | ||
971 | for (i = 0; i < 32; i ++) | |
972 | { | |
973 | sprintf(device, "/dev/ttyd%c", funky_hex[i]); | |
974 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
975 | { | |
976 | close(fd); | |
977 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Standard Serial Port #%d\"\n", | |
978 | device, i + 1); | |
979 | } | |
980 | } | |
981 | ||
982 | /* | |
983 | * Cyclades ports... | |
984 | */ | |
985 | ||
986 | for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ | |
987 | for (j = 0; j < 32; j ++) | |
988 | { | |
989 | sprintf(device, "/dev/ttyc%d%c", i, funky_hex[j]); | |
990 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
991 | { | |
992 | close(fd); | |
993 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n", | |
994 | device, i, j + 1); | |
995 | } | |
996 | ||
997 | sprintf(device, "/dev/ttyC%d%c", i, funky_hex[j]); | |
998 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
999 | { | |
1000 | close(fd); | |
1001 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n", | |
1002 | device, i, j + 1); | |
1003 | } | |
1004 | } | |
1005 | ||
1006 | /* | |
1007 | * Digiboard ports... | |
1008 | */ | |
1009 | ||
1010 | for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ | |
1011 | for (j = 0; j < 32; j ++) | |
1012 | { | |
1013 | sprintf(device, "/dev/ttyD%d%c", i, funky_hex[j]); | |
1014 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
1015 | { | |
1016 | close(fd); | |
1017 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Digiboard #%d Serial Port #%d\"\n", | |
1018 | device, i, j + 1); | |
1019 | } | |
1020 | } | |
1021 | ||
1022 | /* | |
1023 | * Stallion ports... | |
1024 | */ | |
1025 | ||
1026 | for (i = 0; i < 32; i ++) | |
1027 | { | |
1028 | sprintf(device, "/dev/ttyE%c", funky_hex[i]); | |
1029 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
1030 | { | |
1031 | close(fd); | |
1032 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Stallion Serial Port #%d\"\n", | |
1033 | device, i + 1); | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | /* | |
1038 | * SX ports... | |
1039 | */ | |
1040 | ||
1041 | for (i = 0; i < 128; i ++) | |
1042 | { | |
1043 | sprintf(device, "/dev/ttyA%d", i + 1); | |
1044 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
1045 | { | |
1046 | close(fd); | |
1047 | printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n", | |
1048 | device, i + 1); | |
1049 | } | |
1050 | } | |
1051 | #elif defined(__NetBSD__) | |
1052 | int i, j; /* Looping vars */ | |
1053 | int fd; /* File descriptor */ | |
1054 | char device[255]; /* Device filename */ | |
1055 | ||
1056 | ||
1057 | /* | |
1058 | * Standard serial ports... | |
1059 | */ | |
1060 | ||
1061 | for (i = 0; i < 4; i ++) | |
1062 | { | |
1063 | sprintf(device, "/dev/tty%02d", i); | |
1064 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
1065 | { | |
1066 | close(fd); | |
1067 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", | |
1068 | device, i + 1); | |
1069 | } | |
1070 | } | |
1071 | ||
1072 | /* | |
1073 | * Cyclades-Z ports... | |
1074 | */ | |
1075 | ||
1076 | for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ | |
1077 | for (j = 0; j < 64; j ++) | |
1078 | { | |
1079 | sprintf(device, "/dev/ttyCZ%02d%02d", i, j); | |
1080 | if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) | |
1081 | { | |
1082 | close(fd); | |
1083 | printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Prt #%d\"\n", | |
1084 | device, i, j + 1); | |
1085 | } | |
1086 | } | |
1087 | #elif defined(__APPLE__) | |
1088 | /* | |
1089 | * Standard serial ports on MacOS X... | |
1090 | */ | |
1091 | ||
1092 | kern_return_t kernResult; | |
1093 | mach_port_t masterPort; | |
1094 | io_iterator_t serialPortIterator; | |
1095 | CFMutableDictionaryRef classesToMatch; | |
1096 | io_object_t serialService; | |
1097 | ||
ef416fc2 | 1098 | |
1099 | kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); | |
1100 | if (KERN_SUCCESS != kernResult) | |
1101 | return; | |
1102 | ||
1103 | /* | |
1104 | * Serial devices are instances of class IOSerialBSDClient. | |
1105 | */ | |
1106 | ||
1107 | classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); | |
1108 | if (classesToMatch != NULL) | |
1109 | { | |
1110 | CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), | |
1111 | CFSTR(kIOSerialBSDRS232Type)); | |
1112 | ||
1113 | kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, | |
1114 | &serialPortIterator); | |
1115 | if (kernResult == KERN_SUCCESS) | |
1116 | { | |
1117 | while ((serialService = IOIteratorNext(serialPortIterator))) | |
1118 | { | |
1119 | CFTypeRef serialNameAsCFString; | |
1120 | CFTypeRef bsdPathAsCFString; | |
1121 | char serialName[128]; | |
1122 | char bsdPath[1024]; | |
1123 | Boolean result; | |
1124 | ||
1125 | ||
1126 | serialNameAsCFString = | |
1127 | IORegistryEntryCreateCFProperty(serialService, | |
1128 | CFSTR(kIOTTYDeviceKey), | |
1129 | kCFAllocatorDefault, 0); | |
1130 | if (serialNameAsCFString) | |
1131 | { | |
1132 | result = CFStringGetCString(serialNameAsCFString, serialName, | |
1133 | sizeof(serialName), | |
1134 | kCFStringEncodingASCII); | |
1135 | CFRelease(serialNameAsCFString); | |
1136 | ||
1137 | if (result) | |
1138 | { | |
1139 | bsdPathAsCFString = | |
1140 | IORegistryEntryCreateCFProperty(serialService, | |
1141 | CFSTR(kIOCalloutDeviceKey), | |
1142 | kCFAllocatorDefault, 0); | |
1143 | if (bsdPathAsCFString) | |
1144 | { | |
1145 | result = CFStringGetCString(bsdPathAsCFString, bsdPath, | |
1146 | sizeof(bsdPath), | |
1147 | kCFStringEncodingASCII); | |
1148 | CFRelease(bsdPathAsCFString); | |
1149 | ||
1150 | if (result) | |
89d46774 | 1151 | printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", |
1152 | bsdPath, serialName); | |
ef416fc2 | 1153 | } |
1154 | } | |
1155 | } | |
1156 | ||
1157 | IOObjectRelease(serialService); | |
1158 | } | |
1159 | ||
89d46774 | 1160 | /* |
1161 | * Release the iterator. | |
1162 | */ | |
1163 | ||
1164 | IOObjectRelease(serialPortIterator); | |
ef416fc2 | 1165 | } |
1166 | } | |
1167 | #endif | |
1168 | } | |
1169 | ||
1170 | ||
1171 | /* | |
89d46774 | 1172 | * End of "$Id: serial.c 5400 2006-04-14 19:04:02Z mike $". |
ef416fc2 | 1173 | */ |