1package term 2 3import ( 4 "os" 5 "syscall" 6 "unsafe" 7 8 "github.com/pkg/term/termios" 9 "golang.org/x/sys/unix" 10) 11 12type attr unix.Termios 13 14func (a *attr) getSpeed() (int, error) { 15 // We generally only care about ospeed, since that's what would 16 // be used for padding characters, for example. 17 18 rate := termios.Cfgetospeed((*unix.Termios)(a)) 19 20 switch rate { 21 case unix.B50: 22 return 50, nil 23 case unix.B75: 24 return 75, nil 25 case unix.B110: 26 return 110, nil 27 case unix.B134: 28 return 134, nil 29 case unix.B150: 30 return 150, nil 31 case unix.B200: 32 return 200, nil 33 case unix.B300: 34 return 300, nil 35 case unix.B600: 36 return 600, nil 37 case unix.B1200: 38 return 1200, nil 39 case unix.B1800: 40 return 1800, nil 41 case unix.B2400: 42 return 2400, nil 43 case unix.B4800: 44 return 4800, nil 45 case unix.B9600: 46 return 9600, nil 47 case unix.B19200: 48 return 19200, nil 49 case unix.B38400: 50 return 38400, nil 51 case unix.B57600: 52 return 57600, nil 53 case unix.B115200: 54 return 115200, nil 55 case unix.B230400: 56 return 230400, nil 57 case unix.B460800: 58 return 460800, nil 59 case unix.B921600: 60 return 921600, nil 61 default: 62 return 0, unix.EINVAL 63 } 64} 65 66func (a *attr) setSpeed(baud int) error { 67 var rate uint32 68 switch baud { 69 case 50: 70 rate = unix.B50 71 case 75: 72 rate = unix.B75 73 case 110: 74 rate = unix.B110 75 case 134: 76 rate = unix.B134 77 case 150: 78 rate = unix.B150 79 case 200: 80 rate = unix.B200 81 case 300: 82 rate = unix.B300 83 case 600: 84 rate = unix.B600 85 case 1200: 86 rate = unix.B1200 87 case 1800: 88 rate = unix.B1800 89 case 2400: 90 rate = unix.B2400 91 case 4800: 92 rate = unix.B4800 93 case 9600: 94 rate = unix.B9600 95 case 19200: 96 rate = unix.B19200 97 case 38400: 98 rate = unix.B38400 99 case 57600: 100 rate = unix.B57600 101 case 115200: 102 rate = unix.B115200 103 case 230400: 104 rate = unix.B230400 105 case 460800: 106 rate = unix.B460800 107 case 921600: 108 rate = unix.B921600 109 default: 110 return unix.EINVAL 111 } 112 113 err := termios.Cfsetispeed((*unix.Termios)(a), uintptr(rate)) 114 if err != nil { 115 return err 116 } 117 118 err = termios.Cfsetospeed((*unix.Termios)(a), uintptr(rate)) 119 if err != nil { 120 return err 121 } 122 123 return nil 124} 125 126// Open opens an asynchronous communications port. 127func Open(name string, options ...func(*Term) error) (*Term, error) { 128 129 // copied from https://github.com/kofemann/opensolaris/blob/master/usr/src/uts/common/sys/stropts.h#L229 130 // to avoid cgo dependency. 131 const ( 132 STR = ('S' << 8) 133 I_PUSH = (STR | 02) 134 ) 135 136 fd, e := unix.Open(name, unix.O_NOCTTY|unix.O_CLOEXEC|unix.O_NDELAY|unix.O_RDWR, 0666) 137 if e != nil { 138 return nil, &os.PathError{"open", name, e} 139 } 140 141 modules := [2]string{"ptem", "ldterm"} 142 for _, mod := range modules { 143 err := unix.IoctlSetInt(fd, I_PUSH, int(uintptr(unsafe.Pointer(syscall.StringBytePtr(mod))))) 144 if err != nil { 145 return nil, err 146 } 147 } 148 149 orig, err := termios.Tcgetattr(uintptr(t.fd)) 150 if err != nil { 151 return nil, err 152 } 153 t := Term{name: name, fd: fd, *orig} 154 155 if err := t.SetOption(options...); err != nil { 156 return nil, err 157 } 158 159 return &t, unix.SetNonblock(t.fd, false) 160} 161 162// Restore restores the state of the terminal captured at the point that 163// the terminal was originally opened. 164func (t *Term) Restore() error { 165 return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, &t.orig) 166} 167