Home | History | Annotate | Line # | Download | only in common
linux_ioctl.c revision 1.3
      1 /*	$NetBSD: linux_ioctl.c,v 1.3 1995/06/24 20:20:18 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Frank van der Linden
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *      This product includes software developed for the NetBSD Project
     18  *      by Frank van der Linden
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/param.h>
     35 #include <sys/proc.h>
     36 #include <sys/systm.h>
     37 #include <sys/file.h>
     38 #include <sys/filedesc.h>
     39 #include <sys/ioctl.h>
     40 #include <sys/termios.h>
     41 #include <sys/tty.h>
     42 #include <sys/socket.h>
     43 #include <sys/ioctl.h>
     44 #include <sys/mount.h>
     45 #include <net/if.h>
     46 #include <sys/sockio.h>
     47 
     48 #include <sys/syscallargs.h>
     49 #include <compat/linux/linux_types.h>
     50 #include <compat/linux/linux_ioctl.h>
     51 #include <compat/linux/linux_sockio.h>
     52 #include <compat/linux/linux_util.h>
     53 #include <compat/linux/linux_syscallargs.h>
     54 
     55 static speed_t linux_speeds[] = {
     56 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
     57 	9600, 19200, 38400, 57600, 115200
     58 };
     59 
     60 static int linux_spmasks[] = {
     61 	LINUX_B0, LINUX_B50, LINUX_B75, LINUX_B110, LINUX_B134, LINUX_B150,
     62 	LINUX_B200, LINUX_B300, LINUX_B600, LINUX_B1200, LINUX_B1800,
     63 	LINUX_B2400, LINUX_B4800, LINUX_B9600, LINUX_B19200, LINUX_B38400,
     64 	LINUX_B57600, LINUX_B115200
     65 };
     66 
     67 /*
     68  * Deal with termio ioctl cruft. This doesn't look very good..
     69  * XXX too much code duplication, obviously..
     70  *
     71  * The conversion routines between Linux and BSD structures assume
     72  * that the fields are already filled with the current values,
     73  * so that fields present in BSD but not in Linux keep their current
     74  * values.
     75  */
     76 
     77 static int
     78 linux_termio_to_bsd_termios(lt, bts)
     79 	register struct linux_termio *lt;
     80 	register struct termios *bts;
     81 {
     82 	int index;
     83 
     84 	bts->c_iflag = 0;
     85 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNBRK, IGNBRK);
     86 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_BRKINT, BRKINT);
     87 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNPAR, IGNPAR);
     88 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INPCK, INPCK);
     89 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ISTRIP, ISTRIP);
     90 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INLCR, INLCR);
     91 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNCR, IGNCR);
     92 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ICRNL, ICRNL);
     93 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXON, IXON);
     94 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXANY, IXANY);
     95 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXOFF, IXOFF);
     96 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IMAXBEL, IMAXBEL);
     97 
     98 	bts->c_oflag = 0;
     99 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_OPOST, OPOST);
    100 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_ONLCR, ONLCR);
    101 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_XTABS, OXTABS);
    102 
    103 	/*
    104 	 * This could have been:
    105 	 * bts->c_cflag = (lt->c_flag & LINUX_CSIZE) << 4
    106 	 * But who knows, those values might perhaps change one day.
    107 	 */
    108 	switch (lt->c_cflag & LINUX_CSIZE) {
    109 	case LINUX_CS5:
    110 		bts->c_cflag = CS5;
    111 		break;
    112 	case LINUX_CS6:
    113 		bts->c_cflag = CS6;
    114 		break;
    115 	case LINUX_CS7:
    116 		bts->c_cflag = CS7;
    117 		break;
    118 	case LINUX_CS8:
    119 		bts->c_cflag = CS8;
    120 		break;
    121 	}
    122 
    123 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CSTOPB, CSTOPB);
    124 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CREAD, CREAD);
    125 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARENB, PARENB);
    126 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARODD, PARODD);
    127 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_HUPCL, HUPCL);
    128 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CLOCAL, CLOCAL);
    129 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CRTSCTS, CRTSCTS);
    130 
    131 	bts->c_lflag = 0;
    132 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ISIG, ISIG);
    133 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ICANON, ICANON);
    134 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHO, ECHO);
    135 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOE, ECHOE);
    136 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOK, ECHOK);
    137 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHONL, ECHONL);
    138 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_NOFLSH, NOFLSH);
    139 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_TOSTOP, TOSTOP);
    140 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOCTL, ECHOCTL);
    141 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOPRT, ECHOPRT);
    142 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOKE, ECHOKE);
    143 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_FLUSHO, FLUSHO);
    144 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_PENDIN, PENDIN);
    145 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_IEXTEN, IEXTEN);
    146 
    147 	index = lt->c_cflag & LINUX_CBAUD;
    148 	if (index & LINUX_CBAUDEX)
    149 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
    150 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
    151 
    152 	bts->c_cc[VINTR] = lt->c_cc[LINUX_VINTR];
    153 	bts->c_cc[VQUIT] = lt->c_cc[LINUX_VQUIT];
    154 	bts->c_cc[VERASE] = lt->c_cc[LINUX_VERASE];
    155 	bts->c_cc[VKILL] = lt->c_cc[LINUX_VKILL];
    156 	bts->c_cc[VEOF] = lt->c_cc[LINUX_VEOF];
    157 	bts->c_cc[VTIME] = lt->c_cc[LINUX_VTIME];
    158 	bts->c_cc[VMIN] = lt->c_cc[LINUX_VMIN];
    159 }
    160 
    161 static int
    162 bsd_termios_to_linux_termio(bts, lt)
    163 	register struct termios *bts;
    164 	register struct linux_termio *lt;
    165 {
    166 	int i, mask;
    167 
    168 	lt->c_iflag = 0;
    169 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
    170 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
    171 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
    172 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
    173 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
    174 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
    175 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
    176 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
    177 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
    178 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
    179 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
    180 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
    181 
    182 	lt->c_oflag = 0;
    183 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
    184 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
    185 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
    186 
    187 	switch (bts->c_cflag & CSIZE) {
    188 	case CS5:
    189 		lt->c_cflag = LINUX_CS5;
    190 		break;
    191 	case CS6:
    192 		lt->c_cflag = LINUX_CS6;
    193 		break;
    194 	case CS7:
    195 		lt->c_cflag = LINUX_CS7;
    196 		break;
    197 	case CS8:
    198 		lt->c_cflag = LINUX_CS8;
    199 		break;
    200 	}
    201 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
    202 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
    203 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
    204 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
    205 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
    206 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
    207 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
    208 
    209 	lt->c_lflag = 0;
    210 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
    211 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
    212 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
    213 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
    214 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
    215 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
    216 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
    217 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
    218 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
    219 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
    220 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
    221 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
    222 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
    223 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
    224 
    225 	mask = LINUX_B9600;	/* XXX default value should this be 0? */
    226 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
    227 		if (bts->c_ospeed == linux_speeds[i]) {
    228 			mask = linux_spmasks[i];
    229 			break;
    230 		}
    231 	}
    232 	lt->c_cflag |= mask;
    233 
    234 	lt->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
    235 	lt->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
    236 	lt->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
    237 	lt->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
    238 	lt->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
    239 	lt->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
    240 	lt->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
    241 	lt->c_cc[LINUX_VSWTC] = 0;
    242 
    243 	/* XXX should be fixed someday */
    244 	lt->c_line = 0;
    245 }
    246 
    247 static int
    248 linux_termios_to_bsd_termios(lts, bts)
    249 	register struct linux_termios *lts;
    250 	register struct termios *bts;
    251 {
    252 	int index;
    253 
    254 	bts->c_iflag = 0;
    255 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNBRK, IGNBRK);
    256 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_BRKINT, BRKINT);
    257 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNPAR, IGNPAR);
    258 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INPCK, INPCK);
    259 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ISTRIP, ISTRIP);
    260 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INLCR, INLCR);
    261 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNCR, IGNCR);
    262 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ICRNL, ICRNL);
    263 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXON, IXON);
    264 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXANY, IXANY);
    265 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXOFF, IXOFF);
    266 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IMAXBEL, IMAXBEL);
    267 
    268 	bts->c_oflag = 0;
    269 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_OPOST, OPOST);
    270 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_ONLCR, ONLCR);
    271 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_XTABS, OXTABS);
    272 
    273 	bts->c_cflag = 0;
    274 	switch (lts->c_cflag & LINUX_CSIZE) {
    275 	case LINUX_CS5:
    276 		bts->c_cflag = CS5;
    277 		break;
    278 	case LINUX_CS6:
    279 		bts->c_cflag = CS6;
    280 		break;
    281 	case LINUX_CS7:
    282 		bts->c_cflag = CS7;
    283 		break;
    284 	case LINUX_CS8:
    285 		bts->c_cflag = CS8;
    286 		break;
    287 	}
    288 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CSTOPB, CSTOPB);
    289 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CREAD, CREAD);
    290 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARENB, PARENB);
    291 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARODD, PARODD);
    292 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_HUPCL, HUPCL);
    293 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CLOCAL, CLOCAL);
    294 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CRTSCTS, CRTSCTS);
    295 
    296 	bts->c_lflag = 0;
    297 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ISIG, ISIG);
    298 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ICANON, ICANON);
    299 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHO, ECHO);
    300 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOE, ECHOE);
    301 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOK, ECHOK);
    302 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHONL, ECHONL);
    303 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_NOFLSH, NOFLSH);
    304 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_TOSTOP, TOSTOP);
    305 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOCTL, ECHOCTL);
    306 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOPRT, ECHOPRT);
    307 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOKE, ECHOKE);
    308 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_FLUSHO, FLUSHO);
    309 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_PENDIN, PENDIN);
    310 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_IEXTEN, IEXTEN);
    311 
    312 	index = lts->c_cflag & LINUX_CBAUD;
    313 	if (index & LINUX_CBAUDEX)
    314 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
    315 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
    316 
    317 	bts->c_cc[VINTR] = lts->c_cc[LINUX_VINTR];
    318 	bts->c_cc[VQUIT] = lts->c_cc[LINUX_VQUIT];
    319 	bts->c_cc[VERASE] = lts->c_cc[LINUX_VERASE];
    320 	bts->c_cc[VKILL] = lts->c_cc[LINUX_VKILL];
    321 	bts->c_cc[VEOF] = lts->c_cc[LINUX_VEOF];
    322 	bts->c_cc[VTIME] = lts->c_cc[LINUX_VTIME];
    323 	bts->c_cc[VMIN] = lts->c_cc[LINUX_VMIN];
    324 	bts->c_cc[VEOL] = lts->c_cc[LINUX_VEOL];
    325 	bts->c_cc[VEOL2] = lts->c_cc[LINUX_VEOL2];
    326 	bts->c_cc[VWERASE] = lts->c_cc[LINUX_VWERASE];
    327 	bts->c_cc[VSUSP] = lts->c_cc[LINUX_VSUSP];
    328 	bts->c_cc[VSTART] = lts->c_cc[LINUX_VSTART];
    329 	bts->c_cc[VSTOP] = lts->c_cc[LINUX_VSTOP];
    330 	bts->c_cc[VLNEXT] = lts->c_cc[LINUX_VLNEXT];
    331 	bts->c_cc[VDISCARD] = lts->c_cc[LINUX_VDISCARD];
    332 	bts->c_cc[VREPRINT] = lts->c_cc[LINUX_VREPRINT];
    333 }
    334 
    335 static int
    336 bsd_termios_to_linux_termios(bts, lts)
    337 	register struct termios *bts;
    338 	register struct linux_termios *lts;
    339 {
    340 	int i, mask;
    341 
    342 	lts->c_iflag = 0;
    343 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
    344 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
    345 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
    346 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
    347 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
    348 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
    349 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
    350 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
    351 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
    352 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
    353 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
    354 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
    355 
    356 	lts->c_oflag = 0;
    357 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
    358 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
    359 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
    360 
    361 	switch (bts->c_cflag & CSIZE) {
    362 	case CS5:
    363 		lts->c_cflag = LINUX_CS5;
    364 		break;
    365 	case CS6:
    366 		lts->c_cflag = LINUX_CS6;
    367 		break;
    368 	case CS7:
    369 		lts->c_cflag = LINUX_CS7;
    370 		break;
    371 	case CS8:
    372 		lts->c_cflag = LINUX_CS8;
    373 		break;
    374 	}
    375 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS5, LINUX_CS5);
    376 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS6, LINUX_CS6);
    377 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS7, LINUX_CS7);
    378 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS8, LINUX_CS8);
    379 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
    380 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
    381 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
    382 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
    383 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
    384 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
    385 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
    386 
    387 	lts->c_lflag = 0;
    388 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
    389 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
    390 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
    391 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
    392 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
    393 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
    394 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
    395 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
    396 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
    397 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
    398 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
    399 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
    400 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
    401 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
    402 
    403 	mask = LINUX_B9600;	/* XXX default value */
    404 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
    405 		if (bts->c_ospeed == linux_speeds[i]) {
    406 			mask = linux_spmasks[i];
    407 			break;
    408 		}
    409 	}
    410 	lts->c_cflag |= mask;
    411 
    412 	lts->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
    413 	lts->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
    414 	lts->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
    415 	lts->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
    416 	lts->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
    417 	lts->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
    418 	lts->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
    419 	lts->c_cc[LINUX_VEOL] = bts->c_cc[VEOL];
    420 	lts->c_cc[LINUX_VEOL2] = bts->c_cc[VEOL2];
    421 	lts->c_cc[LINUX_VWERASE] = bts->c_cc[VWERASE];
    422 	lts->c_cc[LINUX_VSUSP] = bts->c_cc[VSUSP];
    423 	lts->c_cc[LINUX_VSTART] = bts->c_cc[VSTART];
    424 	lts->c_cc[LINUX_VSTOP] = bts->c_cc[VSTOP];
    425 	lts->c_cc[LINUX_VLNEXT] = bts->c_cc[VLNEXT];
    426 	lts->c_cc[LINUX_VDISCARD] = bts->c_cc[VDISCARD];
    427 	lts->c_cc[LINUX_VREPRINT] = bts->c_cc[VREPRINT];
    428 	lts->c_cc[LINUX_VSWTC] = 0;
    429 
    430 	/* XXX should be fixed someday */
    431 	lts->c_line = 0;
    432 }
    433 
    434 /*
    435  * Most ioctl command are just converted to their NetBSD values,
    436  * and passed on. The ones that take structure pointers and (flag)
    437  * values need some massaging. This is done the usual way by
    438  * allocating stackgap memory, letting the actual ioctl call do its
    439  * work their and converting back the data afterwards.
    440  */
    441 int
    442 linux_ioctl(p, uap, retval)
    443 	register struct proc *p;
    444 	register struct linux_ioctl_args /* {
    445 		syscallarg(int) fd;
    446 		syscallarg(u_long) com;
    447 		syscallarg(caddr_t) data;
    448 	} */ *uap;
    449 	register_t *retval;
    450 {
    451 	int fd;
    452 	unsigned long com;
    453 	caddr_t data, sg;
    454 	struct file *fp;
    455 	struct filedesc *fdp;
    456 	struct linux_termio tmplt, *alt;
    457 	struct linux_termios tmplts, *alts;
    458 	struct termios tmpbts, *abts;
    459 	struct ioctl_args ia;
    460 	int error, idat, *idatp;
    461 
    462 	fd = SCARG(&ia, fd) = SCARG(uap, fd);
    463 	com = SCARG(uap, com);
    464 	data = SCARG(&ia, data) = SCARG(uap, data);
    465 	retval[0] = 0;
    466 
    467 	fdp = p->p_fd;
    468 	if ((u_int)fd >= fdp->fd_nfiles ||
    469 	    (fp = fdp->fd_ofiles[fd]) == NULL)
    470 		return (EBADF);
    471 
    472 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
    473 		return (EBADF);
    474 
    475 	sg = stackgap_init(p->p_emul);
    476 
    477 	switch (com) {
    478 	case LINUX_TCGETS:
    479 		SCARG(&ia, com) = TIOCGETA;
    480 		abts = stackgap_alloc(&sg, sizeof (*abts));
    481 		SCARG(&ia, data) = (caddr_t) abts;
    482 		if ((error = ioctl(p, &ia, retval)) != 0)
    483 			return error;
    484 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
    485 			return error;
    486 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
    487 		return copyout(&tmplts, data, sizeof tmplts);
    488 	case LINUX_TCSETS:
    489 	case LINUX_TCSETSW:
    490 	case LINUX_TCSETSF:
    491 		switch (com) {
    492 		case LINUX_TCSETS:
    493 			SCARG(&ia, com) = TIOCSETA;
    494 			break;
    495 		case LINUX_TCSETSW:
    496 			SCARG(&ia, com) = TIOCSETAW;
    497 			break;
    498 		case LINUX_TCSETSF:
    499 			SCARG(&ia, com) = TIOCSETAF;
    500 			break;
    501 		}
    502 		if ((error = copyin(data, &tmplts, sizeof tmplts)))
    503 			return error;
    504 		abts = stackgap_alloc(&sg, sizeof tmpbts);
    505 		/*
    506 		 * First fill in all fields, so that we keep the current
    507 		 * values for fields that Linux doesn't know about.
    508 		 */
    509 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
    510 		    (caddr_t) &tmpbts, p)))
    511 			return error;
    512 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
    513 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
    514 			return error;
    515 		SCARG(&ia, data) = (caddr_t) abts;
    516 		return ioctl(p, &ia, retval);
    517 	case LINUX_TCGETA:
    518 		SCARG(&ia, com) = TIOCGETA;
    519 		abts = stackgap_alloc(&sg, sizeof (*abts));
    520 		SCARG(&ia, data) = (caddr_t) abts;
    521 		if ((error = ioctl(p, &ia, retval)) != 0)
    522 			return error;
    523 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
    524 			return error;
    525 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
    526 		return copyout(&tmplt, data, sizeof tmplt);
    527 	case LINUX_TCSETA:
    528 	case LINUX_TCSETAW:
    529 	case LINUX_TCSETAF:
    530 		switch (com) {
    531 		case LINUX_TCSETA:
    532 			SCARG(&ia, com) = TIOCSETA;
    533 			break;
    534 		case LINUX_TCSETAW:
    535 			SCARG(&ia, com) = TIOCSETAW;
    536 			break;
    537 		case LINUX_TCSETAF:
    538 			SCARG(&ia, com) = TIOCSETAF;
    539 			break;
    540 		}
    541 		if ((error = copyin(&tmplt, data, sizeof tmplt)))
    542 			return error;
    543 		abts = stackgap_alloc(&sg, sizeof tmpbts);
    544 		/*
    545 		 * First fill in all fields, so that we keep the current
    546 		 * values for fields that Linux doesn't know about.
    547 		 */
    548 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
    549 		    (caddr_t) &tmpbts, p)))
    550 			return error;
    551 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
    552 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
    553 			return error;
    554 		SCARG(&ia, data) = (caddr_t) abts;
    555 		return ioctl(p, &ia, retval);
    556 	case LINUX_TIOCSETD:
    557 		if ((error = copyin(data, (caddr_t) &idat, sizeof idat)))
    558 			return error;
    559 		switch (idat) {
    560 		case LINUX_N_TTY:
    561 			idat = TTYDISC;
    562 			break;
    563 		case LINUX_N_SLIP:
    564 			idat = SLIPDISC;
    565 			break;
    566 		case LINUX_N_PPP:
    567 			idat = PPPDISC;
    568 			break;
    569 		/*
    570 		 * We can't handle the mouse line discipline Linux has.
    571 		 */
    572 		case LINUX_N_MOUSE:
    573 		default:
    574 			return EINVAL;
    575 		}
    576 
    577 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
    578 		if ((error = copyout(&idat, idatp, sizeof (int))))
    579 			return error;
    580 		SCARG(&ia, com) = TIOCSETD;
    581 		SCARG(&ia, data) = (caddr_t) idatp;
    582 		break;
    583 	case LINUX_TIOCGETD:
    584 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
    585 		SCARG(&ia, com) = TIOCGETD;
    586 		SCARG(&ia, data) = (caddr_t) idatp;
    587 		if ((error = ioctl(p, &ia, retval)))
    588 			return error;
    589 		if ((error = copyin(idatp, (caddr_t) &idat, sizeof (int))))
    590 			return error;
    591 		switch (idat) {
    592 		case TTYDISC:
    593 			idat = LINUX_N_TTY;
    594 			break;
    595 		case SLIPDISC:
    596 			idat = LINUX_N_SLIP;
    597 			break;
    598 		case PPPDISC:
    599 			idat = LINUX_N_PPP;
    600 			break;
    601 		/*
    602 		 * Linux does not have the tablet line discipline.
    603 		 */
    604 		case TABLDISC:
    605 		default:
    606 			idat = -1;	/* XXX What should this be? */
    607 			break;
    608 		}
    609 		return copyout(&idat, data, sizeof (int));
    610 	case LINUX_TIOCGWINSZ:
    611 		SCARG(&ia, com) = TIOCGWINSZ;
    612 		break;
    613 	case LINUX_TIOCSWINSZ:
    614 		SCARG(&ia, com) = TIOCSWINSZ;
    615 		break;
    616 	case LINUX_TIOCGPGRP:
    617 		SCARG(&ia, com) = TIOCGPGRP;
    618 		break;
    619 	case LINUX_TIOCSPGRP:
    620 		SCARG(&ia, com) = TIOCSPGRP;
    621 		break;
    622 	case LINUX_FIONREAD:
    623 		SCARG(&ia, com) = FIONREAD;
    624 		break;
    625 	case LINUX_FIONBIO:
    626 		SCARG(&ia, com) = FIONBIO;
    627 		break;
    628 	case LINUX_FIOASYNC:
    629 		SCARG(&ia, com) = FIOASYNC;
    630 		break;
    631 	case LINUX_TIOCEXCL:
    632 		SCARG(&ia, com) = TIOCEXCL;
    633 		break;
    634 	case LINUX_TIOCNXCL:
    635 		SCARG(&ia, com) = TIOCNXCL;
    636 		break;
    637 	case LINUX_TIOCCONS:
    638 		SCARG(&ia, com) = TIOCCONS;
    639 		break;
    640 	case LINUX_TIOCNOTTY:
    641 		SCARG(&ia, com) = TIOCNOTTY;
    642 		break;
    643 	case LINUX_SIOCADDMULTI:
    644 		SCARG(&ia, com) = SIOCADDMULTI;
    645 		break;
    646 	case LINUX_SIOCDELMULTI:
    647 		SCARG(&ia, com) = SIOCDELMULTI;
    648 		break;
    649 	default:
    650 		return EINVAL;
    651 	}
    652 
    653 	return ioctl(p, &ia, retval);
    654 }
    655