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.14 by gbeauche, 2005-01-30T21:42:14Z

# 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-2005 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  
# Line 53 | Line 60 | static int cfmakeraw(struct termios *ter
60          termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
61          termios_p->c_cflag &= ~(CSIZE|PARENB);
62          termios_p->c_cflag |= CS8;
63 +        return 0;
64   }
65   #endif
66  
# Line 63 | Line 71 | public:
71          XSERDPort(const char *dev)
72          {
73                  device_name = dev;
74 <                is_parallel = false;
74 >                protocol = serial;
75                  fd = -1;
76 +                pid = 0;
77                  input_thread_active = output_thread_active = false;
78  
79                  Set_pthread_attr(&thread_attr, 2);
# Line 100 | Line 109 | public:
109          virtual int16 close(void);
110  
111   private:
112 +        bool open_pty(void);
113          bool configure(uint16 config);
114          void set_handshake(uint32 s, bool with_dtr);
115          static void *input_func(void *arg);
116          static void *output_func(void *arg);
117  
118          const char *device_name;                        // Device name
119 <        bool is_parallel;                                       // Flag: Port is parallel
119 >        enum {serial, parallel, pty, midi}
120 >                protocol;                                               // Type of device
121          int fd;                                                         // FD of device
122 +        pid_t pid;                                                      // PID of child process
123  
124          bool io_killed;                                         // Flag: KillIO called, I/O threads must not call deferred tasks
125          bool quitting;                                          // Flag: Quit threads
# Line 167 | Line 179 | int16 XSERDPort::open(uint16 config)
179          io_killed = false;
180          quitting = false;
181  
182 <        // Open port
183 <        fd = ::open(device_name, O_RDWR);
184 <        if (fd < 0)
185 <                goto open_error;
182 >        // Open port, according to the syntax of the path
183 >        if (device_name[0] == '|') {
184 >                // Open a process via ptys
185 >                if (!open_pty())
186 >                        goto open_error;
187 >        }
188 >        else if (!strcmp(device_name, "midi")) {
189 >                // MIDI:  not yet implemented
190 >                return openErr;
191 >        }
192 >        else {
193 >                // Device special file
194 >                fd = ::open(device_name, O_RDWR);
195 >                if (fd < 0)
196 >                        goto open_error;
197  
198   #if defined(__linux__)
199 <        // Parallel port?
200 <        struct stat st;
201 <        if (fstat(fd, &st) == 0)
202 <                if (S_ISCHR(st.st_mode))
203 <                        is_parallel = (MAJOR(st.st_rdev) == LP_MAJOR);
199 >                // Parallel port?
200 >                struct stat st;
201 >                if (fstat(fd, &st) == 0)
202 >                        if (S_ISCHR(st.st_mode))
203 >                                protocol = ((MAJOR(st.st_rdev) == LP_MAJOR) ? parallel : serial);
204   #elif defined(__FreeBSD__) || defined(__NetBSD__)
205 <        // Parallel port?
206 <        struct stat st;
207 <        if (fstat(fd, &st) == 0)
208 <                if (S_ISCHR(st.st_mode))
209 <                        is_parallel = ((st.st_rdev >> 16) == 16);
205 >                // Parallel port?
206 >                struct stat st;
207 >                if (fstat(fd, &st) == 0)
208 >                        if (S_ISCHR(st.st_mode))
209 >                                protocol = (((st.st_rdev >> 16) == 16) ? parallel : serial);
210   #endif
211 +        }
212  
213          // Configure port for raw mode
214 <        if (!is_parallel) {
214 >        if (protocol == serial) {
215                  if (tcgetattr(fd, &mode) < 0)
216                          goto open_error;
217                  cfmakeraw(&mode);
# Line 279 | Line 303 | int16 XSERDPort::control(uint32 pb, uint
303          switch (code) {
304                  case 1:                 // KillIO
305                          io_killed = true;
306 <                        if (!is_parallel)
306 >                        if (protocol == serial)
307                                  tcflush(fd, TCIOFLUSH);
308                          while (read_pending || write_pending)
309                                  usleep(10000);
# Line 300 | Line 324 | int16 XSERDPort::control(uint32 pb, uint
324                          return noErr;
325  
326                  case kSERDSetBreak:
327 <                        if (!is_parallel)
327 >                        if (protocol == serial)
328                                  tcsendbreak(fd, 0);
329                          return noErr;
330  
# Line 308 | Line 332 | int16 XSERDPort::control(uint32 pb, uint
332                          return noErr;
333  
334                  case kSERDBaudRate: {
335 <                        if (is_parallel)
335 >                        if (protocol != serial)
336                                  return noErr;
337                          uint16 rate = ReadMacInt16(pb + csParam);
338                          speed_t baud_rate;
# Line 349 | Line 373 | int16 XSERDPort::control(uint32 pb, uint
373                                  rate = 57600; baud_rate = B57600;
374                          }
375                          WriteMacInt16(pb + csParam, rate);
376 <                        cfsetispeed(&mode, B115200);
377 <                        cfsetospeed(&mode, B115200);
376 >                        cfsetispeed(&mode, baud_rate);
377 >                        cfsetospeed(&mode, baud_rate);
378                          tcsetattr(fd, TCSANOW, &mode);
379                          return noErr;
380                  }
# Line 361 | Line 385 | int16 XSERDPort::control(uint32 pb, uint
385                          return noErr;
386  
387                  case kSERDMiscOptions:
388 <                        if (is_parallel)
388 >                        if (protocol != serial)
389                                  return noErr;
390                          if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR)
391                                  mode.c_cflag &= ~HUPCL;
# Line 371 | Line 395 | int16 XSERDPort::control(uint32 pb, uint
395                          return noErr;
396  
397                  case kSERDAssertDTR: {
398 <                        if (is_parallel)
398 >                        if (protocol != serial)
399                                  return noErr;
400                          unsigned int status = TIOCM_DTR;
401                          ioctl(fd, TIOCMBIS, &status);
# Line 379 | Line 403 | int16 XSERDPort::control(uint32 pb, uint
403                  }
404  
405                  case kSERDNegateDTR: {
406 <                        if (is_parallel)
406 >                        if (protocol != serial)
407                                  return noErr;
408                          unsigned int status = TIOCM_DTR;
409                          ioctl(fd, TIOCMBIC, &status);
# Line 391 | Line 415 | int16 XSERDPort::control(uint32 pb, uint
415                          return noErr;   // Not supported under Unix
416  
417                  case kSERDResetChannel:
418 <                        if (!is_parallel)
418 >                        if (protocol == serial)
419                                  tcflush(fd, TCIOFLUSH);
420                          return noErr;
421  
422                  case kSERDAssertRTS: {
423 <                        if (is_parallel)
423 >                        if (protocol != serial)
424                                  return noErr;
425                          unsigned int status = TIOCM_RTS;
426                          ioctl(fd, TIOCMBIS, &status);
# Line 404 | Line 428 | int16 XSERDPort::control(uint32 pb, uint
428                  }
429  
430                  case kSERDNegateRTS: {
431 <                        if (is_parallel)
431 >                        if (protocol != serial)
432                                  return noErr;
433                          unsigned int status = TIOCM_RTS;
434                          ioctl(fd, TIOCMBIC, &status);
# Line 412 | Line 436 | int16 XSERDPort::control(uint32 pb, uint
436                  }
437  
438                  case kSERD115KBaud:
439 <                        if (is_parallel)
439 >                        if (protocol != serial)
440                                  return noErr;
441                          cfsetispeed(&mode, B115200);
442                          cfsetospeed(&mode, B115200);
# Line 421 | Line 445 | int16 XSERDPort::control(uint32 pb, uint
445  
446                  case kSERD230KBaud:
447                  case kSERDSetHighSpeed:
448 <                        if (is_parallel)
448 >                        if (protocol != serial)
449                                  return noErr;
450                          cfsetispeed(&mode, B230400);
451                          cfsetospeed(&mode, B230400);
# Line 457 | Line 481 | int16 XSERDPort::status(uint32 pb, uint3
481                          WriteMacInt8(p + staXOffHold, 0);
482                          WriteMacInt8(p + staRdPend, read_pending);
483                          WriteMacInt8(p + staWrPend, write_pending);
484 <                        if (is_parallel) {
484 >                        if (protocol != serial) {
485                                  WriteMacInt8(p + staCtsHold, 0);
486                                  WriteMacInt8(p + staDsrHold, 0);
487                                  WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
# Line 508 | Line 532 | int16 XSERDPort::close()
532          if (fd > 0)
533                  ::close(fd);
534          fd = -1;
535 +
536 +        // Wait for the subprocess to exit
537 +        if (pid)
538 +                waitpid(pid, NULL, 0);
539 +        pid = 0;
540 +
541          return noErr;
542   }
543  
544  
545   /*
546 + * Open a process via ptys
547 + */
548 +
549 + bool XSERDPort::open_pty(void)
550 + {
551 +        // Talk to a process via a pty
552 +        char slave[128];
553 +        int slavefd;
554 +
555 +        protocol = pty;
556 +        if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave)))
557 +                return false;
558 +                
559 +        fflush(stdout);
560 +        fflush(stderr);
561 +        switch (pid = fork()) {
562 +        case -1:                                // error
563 +                return false;
564 +                break;
565 +        case 0:                                 // child
566 +                ::close(fd);
567 +
568 +                /* Make the pseudo tty our controlling tty. */
569 +                pty_make_controlling_tty(&slavefd, slave);
570 +
571 +                ::close(0); dup(slavefd); // Use the slave fd for stdin,
572 +                ::close(1); dup(slavefd); // stdout,
573 +                ::close(2); dup(slavefd); // and stderr.
574 +
575 +                // <should we be more paranoid about closing unused fds?>
576 +                // <should we drop privileges if running setuid?>
577 +
578 +                // Let the shell do the dirty work
579 +                execlp("/bin/sh", "/bin/sh", "-c", ++device_name, 0);
580 +
581 +                // exec failed!
582 +                printf("serial_open:  could not exec %s: %s\n",
583 +                           "/bin/sh", strerror(errno));
584 +                exit(1);
585 +                break;
586 +        default:                                // parent
587 +                // Pid was stored above
588 +                break;
589 +        }
590 +
591 +        return true;
592 + }
593 +
594 +
595 + /*
596   *  Configure serial port with MacOS config word
597   */
598  
599   bool XSERDPort::configure(uint16 config)
600   {
601          D(bug(" configure %04x\n", config));
602 <        if (is_parallel)
602 >        if (protocol != serial)
603                  return true;
604  
605          // Set number of stop bits
# Line 603 | Line 683 | void XSERDPort::set_handshake(uint32 s,
683          D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
684                  ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
685                  ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
686 <        if (is_parallel)
686 >        if (protocol != serial)
687                  return;
688  
689          if (with_dtr) {
# Line 670 | Line 750 | void *XSERDPort::input_func(void *arg)
750                                  WriteMacInt32(s->input_pb + ioActCount, 0);
751                                  WriteMacInt32(s->input_dt + serdtResult, uint16(readErr));
752                          }
753 <        
753 >
754                          // Trigger serial interrupt
755                          D(bug(" triggering serial interrupt\n"));
756                          s->read_done = true;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines