unit dev_tty; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses sysutils, vselinfo, kern_thr, sys_conf, sys_tty; var dev_console:p_cdev; procedure ttyconsdev_init(); //SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, nil); implementation uses errno, vfile, vstat, vuio, vttycom, vpoll, vm, md_tty, vsys_generic, sys_event; { * Operations that are exposed through the character device in /dev. } Function ttydev_open(dev:p_cdev;oflags,devtype:Integer):Integer; var tp:p_tty; begin Writeln('ttydev_open("',dev^.si_name,'",',oflags,',',devtype,')'); tp:=dev^.si_drv1; if (tp=nil) then Exit(EWOULDBLOCK); Result:=0; end; Function ttydev_close(dev:p_cdev;fflag,devtype:Integer):Integer; begin Result:=0; end; Function ttydev_read(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer; var tp:p_tty; error:Integer; begin tp:=dev^.si_drv1; error:=ttydisc_read(tp, uio, ioflag); if (error=ENXIO) then error:=0; Exit(error); end; Function ttydev_write(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer; var tp:p_tty; error:Integer; begin tp:=dev^.si_drv1; error:=ttydisc_write(tp, uio, ioflag); Exit(error); end; Function ttydev_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer; var error:Integer; begin error:=0; case (cmd) of TIOCCBRK, TIOCCONS, TIOCDRAIN, TIOCEXCL, TIOCFLUSH, TIOCNXCL, TIOCSBRK, TIOCSCTTY, TIOCSETA, TIOCSETAF, TIOCSETAW, TIOCSPGRP, TIOCSTART, TIOCSTAT, TIOCSTI, TIOCSTOP, TIOCSWINSZ: begin //error:=tty_wait_background(tp, curthread, SIGTTOU); //if (error) then goto done; end; else; end; Writeln('ttydev_ioctl("',dev^.si_name,'",0x',HexStr(cmd,8),',0x',HexStr(data),',0x',HexStr(fflag,8),')'); //error:=tty_ioctl(tp, cmd, data, fflag, td); //done: Exit(error); end; Function ttydev_poll(dev:p_cdev;events:Integer):Integer; var tp:p_tty; error:Integer; revents:Integer; begin error:=0; revents:=0; tp:=dev^.si_drv1; tty_lock(tp); if (error<>0) then begin Exit((events and (POLLIN or POLLRDNORM)) or POLLHUP); end; if ((events and (POLLIN or POLLRDNORM))<>0) then begin { See if we can read something. } if (ttydisc_read_poll(tp) > 0) then begin revents:=revents or events and (POLLIN or POLLRDNORM); end; end; //if (tp^.t_flags and TF_ZOMBIE) then //begin // { Hangup flag on zombie state. } // revents:=revents or POLLHUP; //end else if ((events and (POLLOUT or POLLWRNORM))<>0) then begin { See if we can write something. } if (ttydisc_write_poll(tp) > 0) then begin revents:=revents or events and (POLLOUT or POLLWRNORM); end; end; if (revents=0) then begin if ((events and (POLLIN or POLLRDNORM))<>0) then begin selrecord(curkthread, @tp^.t_inpoll); end; if ((events and (POLLOUT or POLLWRNORM))<>0) then begin selrecord(curkthread, @tp^.t_outpoll); end; end; tty_unlock(tp); Exit(revents); end; Function ttydev_mmap(dev:p_cdev;offset:vm_ooffset_t;paddr:p_vm_paddr_t;nprot:Integer;memattr:p_vm_memattr_t):Integer; var error:Integer; begin { Handle mmap() through the driver. } error:=EPERM; //error:=ttydevsw_mmap(tp, offset, paddr, nprot, memattr); Exit(error); end; { * kqueue support. } procedure tty_kqops_read_detach(kn:p_knote); var tp:p_tty; begin tp:=kn^.kn_hook; knlist_remove(@tp^.t_inpoll.si_note, kn, 0); end; function tty_kqops_read_event(kn:p_knote;hint:QWORD):Integer; var tp:p_tty; begin Result:=0; tp:=kn^.kn_hook; //tty_lock_assert(tp, MA_OWNED); //if (tty_gone(tp) or tp^.t_flags and TF_ZOMBIE) then //begin // kn^.kn_flags:=kn^.kn_flags or EV_EOF; // Exit(1); //end else begin kn^.kn_data:=ttydisc_read_poll(tp); Exit(ord(kn^.kn_data > 0)); end; end; procedure tty_kqops_write_detach(kn:p_knote); var tp:p_tty; begin tp:=kn^.kn_hook; knlist_remove(@tp^.t_outpoll.si_note, kn, 0); end; function tty_kqops_write_event(kn:p_knote;hint:QWORD):Integer; var tp:p_tty; begin Result:=0; tp:=kn^.kn_hook; //tty_lock_assert(tp, MA_OWNED); //if (tty_gone(tp)) then //begin // kn^.kn_flags:=kn^.kn_flags or EV_EOF; // Exit(1); //end else begin kn^.kn_data:=ttydisc_write_poll(tp); Exit(ord(kn^.kn_data > 0)); end; end; const tty_kqops_read:t_filterops=( f_isfd :1; f_detach:@tty_kqops_read_detach; f_event :@tty_kqops_read_event; ); tty_kqops_write:t_filterops=( f_isfd :1; f_detach:@tty_kqops_write_detach; f_event :@tty_kqops_write_event; ); Function ttydev_kqfilter(dev:p_cdev;kn:p_knote):Integer; var tp:p_tty; error:Integer; begin error:=0; tp:=dev^.si_drv1; case (kn^.kn_filter) of EVFILT_READ: begin kn^.kn_hook:=tp; kn^.kn_fop:=@tty_kqops_read; knlist_add(@tp^.t_inpoll.si_note, kn, 0); end; EVFILT_WRITE: begin kn^.kn_hook:=tp; kn^.kn_fop:=@tty_kqops_write; knlist_add(@tp^.t_outpoll.si_note, kn, 0); end; else error:=EINVAL; end; Exit(error); end; const ttydev_cdevsw:t_cdevsw=( d_version :D_VERSION; d_flags :D_TTY; d_name :'ttydev'; d_open :@ttydev_open; d_close :@ttydev_close; d_read :@ttydev_read; d_write :@ttydev_write; d_ioctl :@ttydev_ioctl; d_poll :@ttydev_poll; d_mmap :@ttydev_mmap; d_kqfilter :@ttydev_kqfilter; ); { * /dev/console handling. } Function ttyconsdev_open(dev:p_cdev;oflags,devtype:Integer):Integer; begin // Result:=ttydev_open(dev, oflags, devtype); end; Function ttyconsdev_write(dev:p_cdev;uio:p_uio;ioflag:Integer):Integer; begin Result:=ttydev_write(dev,uio,ioflag); end; const ttyconsdev_cdevsw:t_cdevsw=( d_version :D_VERSION; d_flags :D_TTY; d_name :'ttyconsdev'; d_open :@ttyconsdev_open; d_close :@ttydev_close; d_read :@ttydev_read; d_write :@ttyconsdev_write; d_ioctl :@ttydev_ioctl; d_poll :@ttydev_poll; d_mmap :@ttydev_mmap; d_kqfilter :@ttydev_kqfilter; ); { * /dev/console is a little different than normal TTY's. When opened, * it determines which TTY to use. When data gets written to it, it * will be logged in the kernel message buffer. } function tty_makedev(tp:p_tty;fmt:PChar;const Args:Array of const):p_cdev; register; var dev:p_cdev; uid:uid_t; gid:gid_t; mode:mode_t; begin // User device. uid :=0; gid :=GID_TTY; mode:=S_IRUSR or S_IWUSR or S_IWGRP; dev:=make_dev_cred(@ttydev_cdevsw, 0, uid, gid, mode, fmt, Args); dev^.si_drv1:=tp; Result:=dev; end; procedure ttyconsdev_init(); begin tty_init( @std_tty[ 0],'[Input ]:',nil,TF_THD_NAME_PREFIX); tty_init( @std_tty[ 1],'[Output]:',nil,TF_THD_NAME_PREFIX); tty_init( @std_tty[ 2],'[Error ]:',nil,TF_THD_NAME_PREFIX); // tty_init(@deci_tty[ 0],'[stdin ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 1],'[stdout]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 2],'[stderr]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 3],'[tty2 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 4],'[tty3 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 5],'[tty4 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 6],'[tty5 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 7],'[tty6 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 8],'[tty7 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[ 9],'[ttya0 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[10],'[ttyb0 ]:',nil,TF_THD_NAME_PREFIX); tty_init(@deci_tty[11],'[ttyc0 ]:',nil,TF_THD_NAME_PREFIX); // tty_init(@debug_tty ,'[Debug ]:',nil,TF_THD_NAME_PREFIX); // dev_console:=make_dev_credf(MAKEDEV_ETERNAL, @ttyconsdev_cdevsw, 0, UID_ROOT, GID_WHEEL, &600, 'console',[]); dev_console^.si_drv1:=@debug_tty; // tty_makedev(@deci_tty[ 0],'deci_stdin' ,[]); tty_makedev(@deci_tty[ 1],'deci_stdout',[]); tty_makedev(@deci_tty[ 2],'deci_stderr',[]); tty_makedev(@deci_tty[ 3],'deci_tty2' ,[]); tty_makedev(@deci_tty[ 4],'deci_tty3' ,[]); tty_makedev(@deci_tty[ 5],'deci_tty4' ,[]); tty_makedev(@deci_tty[ 6],'deci_tty5' ,[]); tty_makedev(@deci_tty[ 7],'deci_tty6' ,[]); tty_makedev(@deci_tty[ 8],'deci_tty7' ,[]); tty_makedev(@deci_tty[ 9],'deci_ttya0' ,[]); tty_makedev(@deci_tty[10],'deci_ttyb0' ,[]); tty_makedev(@deci_tty[11],'deci_ttyc0' ,[]); // if (init_tty<>nil) then begin init_tty(); end; end; end.