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.1.1.1 by cebix, 1999-10-03T14:16:25Z 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-1999 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 <                pthread_attr_init(&thread_attr);
71 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
72 <                if (geteuid() == 0) {
73 <                        pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
74 <                        pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);
75 <                        struct sched_param fifo_param;
76 <                        fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + 2;
77 <                        pthread_attr_setschedparam(&thread_attr, &fifo_param);
78 <                }
79 < #endif
90 >                Set_pthread_attr(&thread_attr, 2);
91          }
92  
93          virtual ~XSERDPort()
# Line 101 | Line 112 | public:
112                  }
113          }
114  
115 <        virtual int16 Open(uint16 config);
116 <        virtual int16 PrimeIn(uint32 pb, uint32 dce);
117 <        virtual int16 PrimeOut(uint32 pb, uint32 dce);
118 <        virtual int16 Control(uint32 pb, uint32 dce, uint16 code);
119 <        virtual int16 Status(uint32 pb, uint32 dce, uint16 code);
120 <        virtual int16 Close(void);
115 >        virtual int16 open(uint16 config);
116 >        virtual int16 prime_in(uint32 pb, uint32 dce);
117 >        virtual int16 prime_out(uint32 pb, uint32 dce);
118 >        virtual int16 control(uint32 pb, uint32 dce, uint16 code);
119 >        virtual int16 status(uint32 pb, uint32 dce, uint16 code);
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 166 | Line 180 | void SerialExit(void)
180   *  Open serial port
181   */
182  
183 < int16 XSERDPort::Open(uint16 config)
183 > int16 XSERDPort::open(uint16 config)
184   {
185          // Don't open NULL name devices
186          if (device_name == NULL)
# Line 176 | 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 < #ifdef __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);
215 < #elif defined(__FreeBSD__)
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);
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 >                                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 >                                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 208 | Line 234 | int16 XSERDPort::Open(uint16 config)
234          configure(config);
235  
236          // Start input/output threads
237 +        input_thread_cancel = false;
238 +        output_thread_cancel = false;
239          if (sem_init(&input_signal, 0, 0) < 0)
240                  goto open_error;
241          if (sem_init(&output_signal, 0, 0) < 0)
# Line 238 | Line 266 | open_error:
266                  output_thread_active = false;
267          }
268          if (fd > 0) {
269 <                close(fd);
269 >                ::close(fd);
270                  fd = -1;
271          }
272          return openErr;
# Line 249 | Line 277 | open_error:
277   *  Read data from port
278   */
279  
280 < int16 XSERDPort::PrimeIn(uint32 pb, uint32 dce)
280 > int16 XSERDPort::prime_in(uint32 pb, uint32 dce)
281   {
282          // Send input command to input_thread
283          read_done = false;
# Line 265 | Line 293 | int16 XSERDPort::PrimeIn(uint32 pb, uint
293   *  Write data to port
294   */
295  
296 < int16 XSERDPort::PrimeOut(uint32 pb, uint32 dce)
296 > int16 XSERDPort::prime_out(uint32 pb, uint32 dce)
297   {
298          // Send output command to output_thread
299          write_done = false;
# Line 281 | Line 309 | int16 XSERDPort::PrimeOut(uint32 pb, uin
309   *      Control calls
310   */
311  
312 < int16 XSERDPort::Control(uint32 pb, uint32 dce, uint16 code)
312 > int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
313   {
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 307 | 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 315 | 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 356 | 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 368 | 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 378 | 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 386 | 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 398 | 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 411 | 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 419 | 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 428 | 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 446 | Line 474 | int16 XSERDPort::Control(uint32 pb, uint
474   *      Status calls
475   */
476  
477 < int16 XSERDPort::Status(uint32 pb, uint32 dce, uint16 code)
477 > int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code)
478   {
479          switch (code) {
480                  case kSERDInputCount: {
# Line 464 | 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 493 | Line 521 | int16 XSERDPort::Status(uint32 pb, uint3
521   *      Close serial port
522   */
523  
524 < int16 XSERDPort::Close()
524 > int16 XSERDPort::close()
525   {
526          // Kill threads
527          if (input_thread_active) {
# Line 513 | Line 541 | int16 XSERDPort::Close()
541  
542          // Close port
543          if (fd > 0)
544 <                close(fd);
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 610 | 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 663 | Line 747 | void *XSERDPort::input_func(void *arg)
747                  // KillIO called? Then simply return
748                  if (s->io_killed) {
749  
750 <                        WriteMacInt16(s->input_pb + ioResult, abortErr);
750 >                        WriteMacInt16(s->input_pb + ioResult, uint16(abortErr));
751                          WriteMacInt32(s->input_pb + ioActCount, 0);
752                          s->read_pending = s->read_done = false;
753  
# Line 675 | Line 759 | void *XSERDPort::input_func(void *arg)
759                                  WriteMacInt32(s->input_dt + serdtResult, noErr);
760                          } else {
761                                  WriteMacInt32(s->input_pb + ioActCount, 0);
762 <                                WriteMacInt32(s->input_dt + serdtResult, readErr);
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;
# Line 723 | Line 807 | void *XSERDPort::output_func(void *arg)
807                  // KillIO called? Then simply return
808                  if (s->io_killed) {
809  
810 <                        WriteMacInt16(s->output_pb + ioResult, abortErr);
810 >                        WriteMacInt16(s->output_pb + ioResult, uint16(abortErr));
811                          WriteMacInt32(s->output_pb + ioActCount, 0);
812                          s->write_pending = s->write_done = false;
813  
# Line 735 | Line 819 | void *XSERDPort::output_func(void *arg)
819                                  WriteMacInt32(s->output_dt + serdtResult, noErr);
820                          } else {
821                                  WriteMacInt32(s->output_pb + ioActCount, 0);
822 <                                WriteMacInt32(s->output_dt + serdtResult, writErr);
822 >                                WriteMacInt32(s->output_dt + serdtResult, uint16(writErr));
823                          }
824          
825                          // Trigger serial interrupt

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines