ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/serial_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/serial_unix.cpp (file contents):
Revision 1.10 by cebix, 2002-02-07T16:10:55Z vs.
Revision 1.17 by asvitkine, 2010-10-19T03:30:20Z

# Line 1 | Line 1
1   /*
2   *  serial_unix.cpp - Serial device driver, Unix specific stuff
3   *
4 < *  Basilisk II (C) 1997-2002 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 22 | Line 22
22  
23   #include <sys/ioctl.h>
24   #include <sys/stat.h>
25 + #include <sys/wait.h>
26   #include <pthread.h>
27   #include <semaphore.h>
28   #include <termios.h>
29 + #include <errno.h>
30   #ifdef __linux__
31   #include <linux/lp.h>
32   #include <linux/major.h>
# Line 38 | Line 40
40   #include "serial.h"
41   #include "serial_defs.h"
42  
43 + extern "C" {
44 + #include "sshpty.h"
45 + }
46 +
47 +
48   #define DEBUG 0
49   #include "debug.h"
50  
51   #define MONITOR 0
52  
53  
54 + // IRIX missing or unsupported defines
55 + #ifdef sgi
56 + #ifndef CRTSCTS
57 + #define CRTSCTS CNEW_RTSCTS
58 + #endif
59 + #ifndef B230400
60 + #define B230400 B115200
61 + #endif
62 + #endif
63 +
64 +
65   // Missing functions
66   #ifndef HAVE_CFMAKERAW
67   static int cfmakeraw(struct termios *termios_p)
# Line 53 | Line 71 | static int cfmakeraw(struct termios *ter
71          termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
72          termios_p->c_cflag &= ~(CSIZE|PARENB);
73          termios_p->c_cflag |= CS8;
74 +        return 0;
75   }
76   #endif
77  
# Line 63 | Line 82 | public:
82          XSERDPort(const char *dev)
83          {
84                  device_name = dev;
85 <                is_parallel = false;
85 >                protocol = serial;
86                  fd = -1;
87 +                pid = 0;
88                  input_thread_active = output_thread_active = false;
89  
90                  Set_pthread_attr(&thread_attr, 2);
# Line 100 | Line 120 | public:
120          virtual int16 close(void);
121  
122   private:
123 +        bool open_pty(void);
124          bool configure(uint16 config);
125          void set_handshake(uint32 s, bool with_dtr);
126          static void *input_func(void *arg);
127          static void *output_func(void *arg);
128  
129          const char *device_name;                        // Device name
130 <        bool is_parallel;                                       // Flag: Port is parallel
130 >        enum {serial, parallel, pty, midi}
131 >                protocol;                                               // Type of device
132          int fd;                                                         // FD of device
133 +        pid_t pid;                                                      // PID of child process
134  
135          bool io_killed;                                         // Flag: KillIO called, I/O threads must not call deferred tasks
136          bool quitting;                                          // Flag: Quit threads
# Line 167 | Line 190 | int16 XSERDPort::open(uint16 config)
190          io_killed = false;
191          quitting = false;
192  
193 <        // Open port
194 <        fd = ::open(device_name, O_RDWR);
195 <        if (fd < 0)
196 <                goto open_error;
193 >        // Open port, according to the syntax of the path
194 >        if (device_name[0] == '|') {
195 >                // Open a process via ptys
196 >                if (!open_pty())
197 >                        goto open_error;
198 >        }
199 >        else if (!strcmp(device_name, "midi")) {
200 >                // MIDI:  not yet implemented
201 >                return openErr;
202 >        }
203 >        else {
204 >                // Device special file
205 >                fd = ::open(device_name, O_RDWR);
206 >                if (fd < 0)
207 >                        goto open_error;
208  
209   #if defined(__linux__)
210 <        // Parallel port?
211 <        struct stat st;
212 <        if (fstat(fd, &st) == 0)
213 <                if (S_ISCHR(st.st_mode))
214 <                        is_parallel = (MAJOR(st.st_rdev) == LP_MAJOR);
210 >                // Parallel port?
211 >                struct stat st;
212 >                if (fstat(fd, &st) == 0)
213 >                        if (S_ISCHR(st.st_mode))
214 >                                protocol = ((MAJOR(st.st_rdev) == LP_MAJOR) ? parallel : serial);
215   #elif defined(__FreeBSD__) || defined(__NetBSD__)
216 <        // Parallel port?
217 <        struct stat st;
218 <        if (fstat(fd, &st) == 0)
219 <                if (S_ISCHR(st.st_mode))
220 <                        is_parallel = ((st.st_rdev >> 16) == 16);
216 >                // Parallel port?
217 >                struct stat st;
218 >                if (fstat(fd, &st) == 0)
219 >                        if (S_ISCHR(st.st_mode))
220 >                                protocol = (((st.st_rdev >> 16) == 16) ? parallel : serial);
221   #endif
222 +        }
223  
224          // Configure port for raw mode
225 <        if (!is_parallel) {
225 >        if (protocol == serial) {
226                  if (tcgetattr(fd, &mode) < 0)
227                          goto open_error;
228                  cfmakeraw(&mode);
# Line 279 | Line 314 | int16 XSERDPort::control(uint32 pb, uint
314          switch (code) {
315                  case 1:                 // KillIO
316                          io_killed = true;
317 <                        if (!is_parallel)
317 >                        if (protocol == serial)
318                                  tcflush(fd, TCIOFLUSH);
319                          while (read_pending || write_pending)
320                                  usleep(10000);
# Line 300 | Line 335 | int16 XSERDPort::control(uint32 pb, uint
335                          return noErr;
336  
337                  case kSERDSetBreak:
338 <                        if (!is_parallel)
338 >                        if (protocol == serial)
339                                  tcsendbreak(fd, 0);
340                          return noErr;
341  
# Line 308 | Line 343 | int16 XSERDPort::control(uint32 pb, uint
343                          return noErr;
344  
345                  case kSERDBaudRate: {
346 <                        if (is_parallel)
346 >                        if (protocol != serial)
347                                  return noErr;
348                          uint16 rate = ReadMacInt16(pb + csParam);
349                          speed_t baud_rate;
# Line 349 | Line 384 | int16 XSERDPort::control(uint32 pb, uint
384                                  rate = 57600; baud_rate = B57600;
385                          }
386                          WriteMacInt16(pb + csParam, rate);
387 <                        cfsetispeed(&mode, B115200);
388 <                        cfsetospeed(&mode, B115200);
387 >                        cfsetispeed(&mode, baud_rate);
388 >                        cfsetospeed(&mode, baud_rate);
389                          tcsetattr(fd, TCSANOW, &mode);
390                          return noErr;
391                  }
# Line 361 | Line 396 | int16 XSERDPort::control(uint32 pb, uint
396                          return noErr;
397  
398                  case kSERDMiscOptions:
399 <                        if (is_parallel)
399 >                        if (protocol != serial)
400                                  return noErr;
401                          if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR)
402                                  mode.c_cflag &= ~HUPCL;
# Line 371 | Line 406 | int16 XSERDPort::control(uint32 pb, uint
406                          return noErr;
407  
408                  case kSERDAssertDTR: {
409 <                        if (is_parallel)
409 >                        if (protocol != serial)
410                                  return noErr;
411                          unsigned int status = TIOCM_DTR;
412                          ioctl(fd, TIOCMBIS, &status);
# Line 379 | Line 414 | int16 XSERDPort::control(uint32 pb, uint
414                  }
415  
416                  case kSERDNegateDTR: {
417 <                        if (is_parallel)
417 >                        if (protocol != serial)
418                                  return noErr;
419                          unsigned int status = TIOCM_DTR;
420                          ioctl(fd, TIOCMBIC, &status);
# Line 391 | Line 426 | int16 XSERDPort::control(uint32 pb, uint
426                          return noErr;   // Not supported under Unix
427  
428                  case kSERDResetChannel:
429 <                        if (!is_parallel)
429 >                        if (protocol == serial)
430                                  tcflush(fd, TCIOFLUSH);
431                          return noErr;
432  
433                  case kSERDAssertRTS: {
434 <                        if (is_parallel)
434 >                        if (protocol != serial)
435                                  return noErr;
436                          unsigned int status = TIOCM_RTS;
437                          ioctl(fd, TIOCMBIS, &status);
# Line 404 | Line 439 | int16 XSERDPort::control(uint32 pb, uint
439                  }
440  
441                  case kSERDNegateRTS: {
442 <                        if (is_parallel)
442 >                        if (protocol != serial)
443                                  return noErr;
444                          unsigned int status = TIOCM_RTS;
445                          ioctl(fd, TIOCMBIC, &status);
# Line 412 | Line 447 | int16 XSERDPort::control(uint32 pb, uint
447                  }
448  
449                  case kSERD115KBaud:
450 <                        if (is_parallel)
450 >                        if (protocol != serial)
451                                  return noErr;
452                          cfsetispeed(&mode, B115200);
453                          cfsetospeed(&mode, B115200);
# Line 421 | Line 456 | int16 XSERDPort::control(uint32 pb, uint
456  
457                  case kSERD230KBaud:
458                  case kSERDSetHighSpeed:
459 <                        if (is_parallel)
459 >                        if (protocol != serial)
460                                  return noErr;
461                          cfsetispeed(&mode, B230400);
462                          cfsetospeed(&mode, B230400);
# Line 457 | Line 492 | int16 XSERDPort::status(uint32 pb, uint3
492                          WriteMacInt8(p + staXOffHold, 0);
493                          WriteMacInt8(p + staRdPend, read_pending);
494                          WriteMacInt8(p + staWrPend, write_pending);
495 <                        if (is_parallel) {
495 >                        if (protocol != serial) {
496                                  WriteMacInt8(p + staCtsHold, 0);
497                                  WriteMacInt8(p + staDsrHold, 0);
498                                  WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
# Line 508 | Line 543 | int16 XSERDPort::close()
543          if (fd > 0)
544                  ::close(fd);
545          fd = -1;
546 +
547 +        // Wait for the subprocess to exit
548 +        if (pid)
549 +                waitpid(pid, NULL, 0);
550 +        pid = 0;
551 +
552          return noErr;
553   }
554  
555  
556   /*
557 + * Open a process via ptys
558 + */
559 +
560 + bool XSERDPort::open_pty(void)
561 + {
562 +        // Talk to a process via a pty
563 +        char slave[128];
564 +        int slavefd;
565 +
566 +        protocol = pty;
567 +        if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave)))
568 +                return false;
569 +                
570 +        fflush(stdout);
571 +        fflush(stderr);
572 +        switch (pid = fork()) {
573 +        case -1:                                // error
574 +                return false;
575 +                break;
576 +        case 0:                                 // child
577 +                ::close(fd);
578 +
579 +                /* Make the pseudo tty our controlling tty. */
580 +                pty_make_controlling_tty(&slavefd, slave);
581 +
582 +                ::close(0); dup(slavefd); // Use the slave fd for stdin,
583 +                ::close(1); dup(slavefd); // stdout,
584 +                ::close(2); dup(slavefd); // and stderr.
585 +
586 +                // <should we be more paranoid about closing unused fds?>
587 +                // <should we drop privileges if running setuid?>
588 +
589 +                // Let the shell do the dirty work
590 +                execlp("/bin/sh", "/bin/sh", "-c", ++device_name, (char *)NULL);
591 +
592 +                // exec failed!
593 +                printf("serial_open:  could not exec %s: %s\n",
594 +                           "/bin/sh", strerror(errno));
595 +                exit(1);
596 +                break;
597 +        default:                                // parent
598 +                // Pid was stored above
599 +                break;
600 +        }
601 +
602 +        return true;
603 + }
604 +
605 +
606 + /*
607   *  Configure serial port with MacOS config word
608   */
609  
610   bool XSERDPort::configure(uint16 config)
611   {
612          D(bug(" configure %04x\n", config));
613 <        if (is_parallel)
613 >        if (protocol != serial)
614                  return true;
615  
616          // Set number of stop bits
# Line 603 | Line 694 | void XSERDPort::set_handshake(uint32 s,
694          D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
695                  ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
696                  ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
697 <        if (is_parallel)
697 >        if (protocol != serial)
698                  return;
699  
700          if (with_dtr) {
# Line 670 | Line 761 | void *XSERDPort::input_func(void *arg)
761                                  WriteMacInt32(s->input_pb + ioActCount, 0);
762                                  WriteMacInt32(s->input_dt + serdtResult, uint16(readErr));
763                          }
764 <        
764 >
765                          // Trigger serial interrupt
766                          D(bug(" triggering serial interrupt\n"));
767                          s->read_done = true;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines