xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_ioctl.c,v 1.10 1996/06/12 05:06:27 gpalmer Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/proc.h>
35 #include <sys/ioctl.h>
36 #include <sys/ioctl_compat.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/tty.h>
40 #include <sys/termios.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <net/if.h>
44 #include <sys/sockio.h>
45 
46 #include <machine/soundcard.h>
47 
48 #include <i386/linux/linux.h>
49 #include <i386/linux/linux_proto.h>
50 
51 struct linux_termio {
52     unsigned short c_iflag;
53     unsigned short c_oflag;
54     unsigned short c_cflag;
55     unsigned short c_lflag;
56     unsigned char c_line;
57     unsigned char c_cc[LINUX_NCC];
58 };
59 
60 
61 struct linux_termios {
62     unsigned long   c_iflag;
63     unsigned long   c_oflag;
64     unsigned long   c_cflag;
65     unsigned long   c_lflag;
66     unsigned char   c_line;
67     unsigned char   c_cc[LINUX_NCCS];
68 };
69 
70 struct linux_winsize {
71     unsigned short ws_row, ws_col;
72     unsigned short ws_xpixel, ws_ypixel;
73 };
74 
75 static struct speedtab sptab[] = {
76     { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 },
77     { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 },
78     { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 },
79     { 2400, 11 }, { 4800, 12 }, { 9600, 13 },
80     { 19200, 14 }, { 38400, 15 },
81     { 57600, 4097 }, { 115200, 4098 }, {-1, -1 }
82 };
83 
84 struct linux_serial_struct {
85         int     type;
86         int     line;
87         int     port;
88         int     irq;
89         int     flags;
90         int     xmit_fifo_size;
91         int     custom_divisor;
92         int     baud_base;
93         unsigned short  close_delay;
94         char    reserved_char[2];
95         int     hub6;
96         unsigned short  closing_wait;
97         unsigned short  closing_wait2;
98         int     reserved[4];
99 };
100 
101 
102 static int
103 linux_to_bsd_speed(int code, struct speedtab *table)
104 {
105     for ( ; table->sp_code != -1; table++)
106 	if (table->sp_code == code)
107 	    return (table->sp_speed);
108     return -1;
109 }
110 
111 static int
112 bsd_to_linux_speed(int speed, struct speedtab *table)
113 {
114     for ( ; table->sp_speed != -1; table++)
115 	if (table->sp_speed == speed)
116 	    return (table->sp_code);
117     return -1;
118 }
119 
120 static void
121 bsd_to_linux_termios(struct termios *bsd_termios,
122 		struct linux_termios *linux_termios)
123 {
124     int i;
125 
126 #ifdef DEBUG
127     printf("LINUX: BSD termios structure (input):\n");
128     printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
129 	   bsd_termios->c_iflag, bsd_termios->c_oflag,
130 	   bsd_termios->c_cflag, bsd_termios->c_lflag,
131 	   bsd_termios->c_ispeed, bsd_termios->c_ospeed);
132     printf("c_cc ");
133     for (i=0; i<NCCS; i++)
134 	printf("%02x ", bsd_termios->c_cc[i]);
135     printf("\n");
136 #endif
137     linux_termios->c_iflag = 0;
138     if (bsd_termios->c_iflag & IGNBRK)
139 	linux_termios->c_iflag |= LINUX_IGNBRK;
140     if (bsd_termios->c_iflag & BRKINT)
141 	linux_termios->c_iflag |= LINUX_BRKINT;
142     if (bsd_termios->c_iflag & IGNPAR)
143 	linux_termios->c_iflag |= LINUX_IGNPAR;
144     if (bsd_termios->c_iflag & PARMRK)
145 	linux_termios->c_iflag |= LINUX_PARMRK;
146     if (bsd_termios->c_iflag & INPCK)
147 	linux_termios->c_iflag |= LINUX_INPCK;
148     if (bsd_termios->c_iflag & ISTRIP)
149 	linux_termios->c_iflag |= LINUX_ISTRIP;
150     if (bsd_termios->c_iflag & INLCR)
151 	linux_termios->c_iflag |= LINUX_INLCR;
152     if (bsd_termios->c_iflag & IGNCR)
153 	linux_termios->c_iflag |= LINUX_IGNCR;
154     if (bsd_termios->c_iflag & ICRNL)
155 	linux_termios->c_iflag |= LINUX_ICRNL;
156     if (bsd_termios->c_iflag & IXON)
157 	linux_termios->c_iflag |= LINUX_IXANY;
158     if (bsd_termios->c_iflag & IXON)
159 	linux_termios->c_iflag |= LINUX_IXON;
160     if (bsd_termios->c_iflag & IXOFF)
161 	linux_termios->c_iflag |= LINUX_IXOFF;
162     if (bsd_termios->c_iflag & IMAXBEL)
163 	linux_termios->c_iflag |= LINUX_IMAXBEL;
164 
165     linux_termios->c_oflag = 0;
166     if (bsd_termios->c_oflag & OPOST)
167 	linux_termios->c_oflag |= LINUX_OPOST;
168     if (bsd_termios->c_oflag & ONLCR)
169 	linux_termios->c_oflag |= LINUX_ONLCR;
170     if (bsd_termios->c_oflag & OXTABS)
171 	linux_termios->c_oflag |= LINUX_XTABS;
172 
173     linux_termios->c_cflag =
174 	bsd_to_linux_speed(bsd_termios->c_ispeed, sptab);
175     linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4;
176     if (bsd_termios->c_cflag & CSTOPB)
177 	linux_termios->c_cflag |= LINUX_CSTOPB;
178     if (bsd_termios->c_cflag & CREAD)
179 	linux_termios->c_cflag |= LINUX_CREAD;
180     if (bsd_termios->c_cflag & PARENB)
181 	linux_termios->c_cflag |= LINUX_PARENB;
182     if (bsd_termios->c_cflag & PARODD)
183 	linux_termios->c_cflag |= LINUX_PARODD;
184     if (bsd_termios->c_cflag & HUPCL)
185 	linux_termios->c_cflag |= LINUX_HUPCL;
186     if (bsd_termios->c_cflag & CLOCAL)
187 	linux_termios->c_cflag |= LINUX_CLOCAL;
188     if (bsd_termios->c_cflag & CRTSCTS)
189 	linux_termios->c_cflag |= LINUX_CRTSCTS;
190 
191     linux_termios->c_lflag = 0;
192     if (bsd_termios->c_lflag & ISIG)
193 	linux_termios->c_lflag |= LINUX_ISIG;
194     if (bsd_termios->c_lflag & ICANON)
195 	linux_termios->c_lflag |= LINUX_ICANON;
196     if (bsd_termios->c_lflag & ECHO)
197 	linux_termios->c_lflag |= LINUX_ECHO;
198     if (bsd_termios->c_lflag & ECHOE)
199 	linux_termios->c_lflag |= LINUX_ECHOE;
200     if (bsd_termios->c_lflag & ECHOK)
201 	linux_termios->c_lflag |= LINUX_ECHOK;
202     if (bsd_termios->c_lflag & ECHONL)
203 	linux_termios->c_lflag |= LINUX_ECHONL;
204     if (bsd_termios->c_lflag & NOFLSH)
205 	linux_termios->c_lflag |= LINUX_NOFLSH;
206     if (bsd_termios->c_lflag & TOSTOP)
207 	linux_termios->c_lflag |= LINUX_TOSTOP;
208     if (bsd_termios->c_lflag & ECHOCTL)
209 	linux_termios->c_lflag |= LINUX_ECHOCTL;
210     if (bsd_termios->c_lflag & ECHOPRT)
211 	linux_termios->c_lflag |= LINUX_ECHOPRT;
212     if (bsd_termios->c_lflag & ECHOKE)
213 	linux_termios->c_lflag |= LINUX_ECHOKE;
214     if (bsd_termios->c_lflag & FLUSHO)
215 	linux_termios->c_lflag |= LINUX_FLUSHO;
216     if (bsd_termios->c_lflag & PENDIN)
217 	linux_termios->c_lflag |= LINUX_PENDIN;
218     if (bsd_termios->c_lflag & IEXTEN)
219 	linux_termios->c_lflag |= LINUX_IEXTEN;
220 
221     for (i=0; i<LINUX_NCCS; i++)
222 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
223     linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR];
224     linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT];
225     linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE];
226     linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL];
227     linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF];
228     linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL];
229     linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN];
230     linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME];
231     linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2];
232     linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE;
233     linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP];
234     linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART];
235     linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP];
236     linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT];
237     linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD];
238     linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE];
239     linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT];
240 
241     for (i=0; i<LINUX_NCCS; i++) {
242       if (linux_termios->c_cc[i] == _POSIX_VDISABLE)
243 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
244     }
245 
246     linux_termios->c_line = 0;
247 #ifdef DEBUG
248     printf("LINUX: LINUX termios structure (output):\n");
249     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
250 	   linux_termios->c_iflag, linux_termios->c_oflag,
251 	   linux_termios->c_cflag, linux_termios->c_lflag,
252 	   linux_termios->c_line);
253     printf("c_cc ");
254     for (i=0; i<LINUX_NCCS; i++)
255 	printf("%02x ", linux_termios->c_cc[i]);
256     printf("\n");
257 #endif
258 }
259 
260 
261 static void
262 linux_to_bsd_termios(struct linux_termios *linux_termios,
263 		struct termios *bsd_termios)
264 {
265     int i;
266 #ifdef DEBUG
267     printf("LINUX: LINUX termios structure (input):\n");
268     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
269 	   linux_termios->c_iflag, linux_termios->c_oflag,
270 	   linux_termios->c_cflag, linux_termios->c_lflag,
271 	   linux_termios->c_line);
272     printf("c_cc ");
273     for (i=0; i<LINUX_NCCS; i++)
274 	printf("%02x ", linux_termios->c_cc[i]);
275     printf("\n");
276 #endif
277     bsd_termios->c_iflag = 0;
278     if (linux_termios->c_iflag & LINUX_IGNBRK)
279 	bsd_termios->c_iflag |= IGNBRK;
280     if (linux_termios->c_iflag & LINUX_BRKINT)
281 	bsd_termios->c_iflag |= BRKINT;
282     if (linux_termios->c_iflag & LINUX_IGNPAR)
283 	bsd_termios->c_iflag |= IGNPAR;
284     if (linux_termios->c_iflag & LINUX_PARMRK)
285 	bsd_termios->c_iflag |= PARMRK;
286     if (linux_termios->c_iflag & LINUX_INPCK)
287 	bsd_termios->c_iflag |= INPCK;
288     if (linux_termios->c_iflag & LINUX_ISTRIP)
289 	bsd_termios->c_iflag |= ISTRIP;
290     if (linux_termios->c_iflag & LINUX_INLCR)
291 	bsd_termios->c_iflag |= INLCR;
292     if (linux_termios->c_iflag & LINUX_IGNCR)
293 	bsd_termios->c_iflag |= IGNCR;
294     if (linux_termios->c_iflag & LINUX_ICRNL)
295 	bsd_termios->c_iflag |= ICRNL;
296     if (linux_termios->c_iflag & LINUX_IXON)
297 	bsd_termios->c_iflag |= IXANY;
298     if (linux_termios->c_iflag & LINUX_IXON)
299 	bsd_termios->c_iflag |= IXON;
300     if (linux_termios->c_iflag & LINUX_IXOFF)
301 	bsd_termios->c_iflag |= IXOFF;
302     if (linux_termios->c_iflag & LINUX_IMAXBEL)
303 	bsd_termios->c_iflag |= IMAXBEL;
304 
305     bsd_termios->c_oflag = 0;
306     if (linux_termios->c_oflag & LINUX_OPOST)
307 	bsd_termios->c_oflag |= OPOST;
308     if (linux_termios->c_oflag & LINUX_ONLCR)
309 	bsd_termios->c_oflag |= ONLCR;
310     if (linux_termios->c_oflag & LINUX_XTABS)
311 	bsd_termios->c_oflag |= OXTABS;
312 
313     bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4;
314     if (linux_termios->c_cflag & LINUX_CSTOPB)
315 	bsd_termios->c_cflag |= CSTOPB;
316     if (linux_termios->c_cflag & LINUX_PARENB)
317 	bsd_termios->c_cflag |= PARENB;
318     if (linux_termios->c_cflag & LINUX_PARODD)
319 	bsd_termios->c_cflag |= PARODD;
320     if (linux_termios->c_cflag & LINUX_HUPCL)
321 	bsd_termios->c_cflag |= HUPCL;
322     if (linux_termios->c_cflag & LINUX_CLOCAL)
323 	bsd_termios->c_cflag |= CLOCAL;
324     if (linux_termios->c_cflag & LINUX_CRTSCTS)
325 	bsd_termios->c_cflag |= CRTSCTS;
326 
327     bsd_termios->c_lflag = 0;
328     if (linux_termios->c_lflag & LINUX_ISIG)
329 	bsd_termios->c_lflag |= ISIG;
330     if (linux_termios->c_lflag & LINUX_ICANON)
331 	bsd_termios->c_lflag |= ICANON;
332     if (linux_termios->c_lflag & LINUX_ECHO)
333 	bsd_termios->c_lflag |= ECHO;
334     if (linux_termios->c_lflag & LINUX_ECHOE)
335 	bsd_termios->c_lflag |= ECHOE;
336     if (linux_termios->c_lflag & LINUX_ECHOK)
337 	bsd_termios->c_lflag |= ECHOK;
338     if (linux_termios->c_lflag & LINUX_ECHONL)
339 	bsd_termios->c_lflag |= ECHONL;
340     if (linux_termios->c_lflag & LINUX_NOFLSH)
341 	bsd_termios->c_lflag |= NOFLSH;
342     if (linux_termios->c_lflag & LINUX_TOSTOP)
343 	bsd_termios->c_lflag |= TOSTOP;
344     if (linux_termios->c_lflag & LINUX_ECHOCTL)
345 	bsd_termios->c_lflag |= ECHOCTL;
346     if (linux_termios->c_lflag & LINUX_ECHOPRT)
347 	bsd_termios->c_lflag |= ECHOPRT;
348     if (linux_termios->c_lflag & LINUX_ECHOKE)
349 	bsd_termios->c_lflag |= ECHOKE;
350     if (linux_termios->c_lflag & LINUX_FLUSHO)
351 	bsd_termios->c_lflag |= FLUSHO;
352     if (linux_termios->c_lflag & LINUX_PENDIN)
353 	bsd_termios->c_lflag |= PENDIN;
354     if (linux_termios->c_lflag & IEXTEN)
355 	bsd_termios->c_lflag |= IEXTEN;
356 
357     for (i=0; i<NCCS; i++)
358 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
359     bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR];
360     bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT];
361     bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE];
362     bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL];
363     bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF];
364     bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL];
365     bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN];
366     bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME];
367     bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2];
368     bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP];
369     bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART];
370     bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP];
371     bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT];
372     bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD];
373     bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE];
374     bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT];
375 
376     for (i=0; i<NCCS; i++) {
377       if (bsd_termios->c_cc[i] == LINUX_POSIX_VDISABLE)
378 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
379     }
380 
381     bsd_termios->c_ispeed = bsd_termios->c_ospeed =
382 	linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab);
383 #ifdef DEBUG
384 	printf("LINUX: BSD termios structure (output):\n");
385 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
386 	       bsd_termios->c_iflag, bsd_termios->c_oflag,
387 	       bsd_termios->c_cflag, bsd_termios->c_lflag,
388 	       bsd_termios->c_ispeed, bsd_termios->c_ospeed);
389 	printf("c_cc ");
390 	for (i=0; i<NCCS; i++)
391 	    printf("%02x ", bsd_termios->c_cc[i]);
392 	printf("\n");
393 #endif
394 }
395 
396 
397 static void
398 bsd_to_linux_termio(struct termios *bsd_termios,
399 		struct linux_termio *linux_termio)
400 {
401   struct linux_termios tmios;
402 
403   bsd_to_linux_termios(bsd_termios, &tmios);
404   linux_termio->c_iflag = tmios.c_iflag;
405   linux_termio->c_oflag = tmios.c_oflag;
406   linux_termio->c_cflag = tmios.c_cflag;
407   linux_termio->c_lflag = tmios.c_lflag;
408   linux_termio->c_line  = tmios.c_line;
409   memcpy(linux_termio->c_cc, tmios.c_cc, LINUX_NCC);
410 }
411 
412 static void
413 linux_to_bsd_termio(struct linux_termio *linux_termio,
414 		struct termios *bsd_termios)
415 {
416   struct linux_termios tmios;
417   int i;
418 
419   tmios.c_iflag = linux_termio->c_iflag;
420   tmios.c_oflag = linux_termio->c_oflag;
421   tmios.c_cflag = linux_termio->c_cflag;
422   tmios.c_lflag = linux_termio->c_lflag;
423 
424   for (i=0; i<LINUX_NCCS; i++)
425     tmios.c_cc[i] = LINUX_POSIX_VDISABLE;
426   memcpy(tmios.c_cc, linux_termio->c_cc, LINUX_NCC);
427 
428   linux_to_bsd_termios(&tmios, bsd_termios);
429 }
430 
431 static void
432 linux_tiocgserial(struct file *fp, struct linux_serial_struct *lss)
433 {
434   if (!fp || !lss)
435     return;
436 
437   lss->type = LINUX_PORT_16550A;
438   lss->flags = 0;
439   lss->close_delay = 0;
440 }
441 
442 static void
443 linux_tiocsserial(struct file *fp, struct linux_serial_struct *lss)
444 {
445   if (!fp || !lss)
446     return;
447 }
448 
449 int
450 linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval)
451 {
452     struct termios bsd_termios;
453     struct linux_termios linux_termios;
454     struct linux_termio linux_termio;
455     struct filedesc *fdp = p->p_fd;
456     struct file *fp;
457     int (*func)(struct file *fp, int com, caddr_t data, struct proc *p);
458     int bsd_line, linux_line;
459     int error;
460 
461 #ifdef DEBUG
462     printf("Linux-emul(%d): ioctl(%d, %04x, *)\n",
463 	   p->p_pid, args->fd, args->cmd);
464 #endif
465     if ((unsigned)args->fd >= fdp->fd_nfiles
466 	|| (fp = fdp->fd_ofiles[args->fd]) == 0)
467 	return EBADF;
468 
469     if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) {
470 	return EBADF;
471     }
472 
473     func = fp->f_ops->fo_ioctl;
474     switch (args->cmd & 0xffff) {
475 
476     case LINUX_TCGETA:
477 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
478 	    return error;
479 	bsd_to_linux_termio(&bsd_termios, &linux_termio);
480 	return copyout((caddr_t)&linux_termio, (caddr_t)args->arg,
481 		       sizeof(linux_termio));
482 
483     case LINUX_TCSETA:
484 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
485 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
486 
487     case LINUX_TCSETAW:
488 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
489 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
490 
491     case LINUX_TCSETAF:
492 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
493 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
494 
495     case LINUX_TCGETS:
496 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
497 	    return error;
498 	bsd_to_linux_termios(&bsd_termios, &linux_termios);
499 	return copyout((caddr_t)&linux_termios, (caddr_t)args->arg,
500 		       sizeof(linux_termios));
501 
502     case LINUX_TCSETS:
503 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
504 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
505 
506     case LINUX_TCSETSW:
507 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
508 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
509 
510     case LINUX_TCSETSF:
511 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
512 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
513 
514     case LINUX_TIOCGPGRP:
515 	args->cmd = TIOCGPGRP;
516 	return ioctl(p, (struct ioctl_args *)args, retval);
517 
518     case LINUX_TIOCSPGRP:
519 	args->cmd = TIOCSPGRP;
520 	return ioctl(p, (struct ioctl_args *)args, retval);
521 
522     case LINUX_TIOCGWINSZ:
523 	args->cmd = TIOCGWINSZ;
524 	return ioctl(p, (struct ioctl_args *)args, retval);
525 
526     case LINUX_TIOCSWINSZ:
527 	args->cmd = TIOCSWINSZ;
528 	return ioctl(p, (struct ioctl_args *)args, retval);
529 
530     case LINUX_FIONREAD:
531 	args->cmd = FIONREAD;
532 	return ioctl(p, (struct ioctl_args *)args, retval);
533 
534     case LINUX_FIONBIO:
535 	args->cmd = FIONBIO;
536 	return ioctl(p, (struct ioctl_args *)args, retval);
537 
538     case LINUX_FIOASYNC:
539 	args->cmd = FIOASYNC;
540 	return ioctl(p, (struct ioctl_args *)args, retval);
541 
542     case LINUX_FIONCLEX:
543 	args->cmd = FIONCLEX;
544 	return ioctl(p, (struct ioctl_args *)args, retval);
545 
546     case LINUX_FIOCLEX:
547 	args->cmd = FIOCLEX;
548 	return ioctl(p, (struct ioctl_args *)args, retval);
549 
550     case LINUX_TIOCEXCL:
551 	args->cmd = TIOCEXCL;
552 	return ioctl(p, (struct ioctl_args *)args, retval);
553 
554     case LINUX_TIOCNXCL:
555 	args->cmd = TIOCNXCL;
556 	return ioctl(p, (struct ioctl_args *)args, retval);
557 
558     case LINUX_TIOCCONS:
559 	args->cmd = TIOCCONS;
560 	return ioctl(p, (struct ioctl_args *)args, retval);
561 
562     case LINUX_TIOCNOTTY:
563 	args->cmd = TIOCNOTTY;
564 	return ioctl(p, (struct ioctl_args *)args, retval);
565 
566     case LINUX_SIOCGIFCONF:
567 	args->cmd = OSIOCGIFCONF;
568 	return ioctl(p, (struct ioctl_args *)args, retval);
569 
570     case LINUX_SIOCGIFFLAGS:
571 	args->cmd = SIOCGIFFLAGS;
572 	return ioctl(p, (struct ioctl_args *)args, retval);
573 
574     case LINUX_SIOCGIFADDR:
575 	args->cmd = OSIOCGIFADDR;
576 	return ioctl(p, (struct ioctl_args *)args, retval);
577 
578     case LINUX_SIOCGIFDSTADDR:
579 	args->cmd = OSIOCGIFDSTADDR;
580 	return ioctl(p, (struct ioctl_args *)args, retval);
581 
582     case LINUX_SIOCGIFBRDADDR:
583 	args->cmd = OSIOCGIFBRDADDR;
584 	return ioctl(p, (struct ioctl_args *)args, retval);
585 
586     case LINUX_SIOCGIFNETMASK:
587 	args->cmd = OSIOCGIFNETMASK;
588 	return ioctl(p, (struct ioctl_args *)args, retval);
589 
590     case LINUX_SIOCADDMULTI:
591 	args->cmd = SIOCADDMULTI;
592 	return ioctl(p, (struct ioctl_args *)args, retval);
593 
594     case LINUX_SIOCDELMULTI:
595 	args->cmd = SIOCDELMULTI;
596 	return ioctl(p, (struct ioctl_args *)args, retval);
597 
598     case LINUX_TIOCSETD:
599 	switch (args->arg) {
600 	case LINUX_N_TTY:
601 	    bsd_line = TTYDISC;
602 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
603 	case LINUX_N_SLIP:
604 	    bsd_line = SLIPDISC;
605 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
606 	case LINUX_N_PPP:
607 	    bsd_line = PPPDISC;
608 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
609 	default:
610 	    return EINVAL;
611 	}
612 
613     case LINUX_TIOCGETD:
614 	bsd_line = TTYDISC;
615 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
616 	    return error;
617 	switch (bsd_line) {
618 	case TTYDISC:
619 	    linux_line = LINUX_N_TTY;
620 	    break;
621 	case SLIPDISC:
622 	    linux_line = LINUX_N_SLIP;
623 	    break;
624 	case PPPDISC:
625 	    linux_line = LINUX_N_PPP;
626 	    break;
627 	default:
628 	    return EINVAL;
629 	}
630 	return copyout(&linux_line, (caddr_t)args->arg,
631 		       sizeof(int));
632 
633     case LINUX_SNDCTL_DSP_RESET:
634 	args->cmd = SNDCTL_DSP_RESET;
635 	return ioctl(p, (struct ioctl_args *)args, retval);
636 
637     case LINUX_SNDCTL_DSP_SYNC:
638 	args->cmd = SNDCTL_DSP_SYNC;
639 	return ioctl(p, (struct ioctl_args *)args, retval);
640 
641     case LINUX_SNDCTL_DSP_SPEED:
642 	args->cmd = SNDCTL_DSP_SPEED;
643 	return ioctl(p, (struct ioctl_args *)args, retval);
644 
645     case LINUX_SNDCTL_DSP_STEREO:
646 	args->cmd = SNDCTL_DSP_STEREO;
647 	return ioctl(p, (struct ioctl_args *)args, retval);
648 
649     case LINUX_SNDCTL_DSP_GETBLKSIZE:
650       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
651 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
652 	return ioctl(p, (struct ioctl_args *)args, retval);
653 
654     case LINUX_SNDCTL_DSP_SETFMT:
655 	args->cmd = SNDCTL_DSP_SETFMT;
656 	return ioctl(p, (struct ioctl_args *)args, retval);
657 
658     case LINUX_SOUND_PCM_WRITE_CHANNELS:
659 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
660 	return ioctl(p, (struct ioctl_args *)args, retval);
661 
662     case LINUX_SOUND_PCM_WRITE_FILTER:
663 	args->cmd = SOUND_PCM_WRITE_FILTER;
664 	return ioctl(p, (struct ioctl_args *)args, retval);
665 
666     case LINUX_SNDCTL_DSP_POST:
667 	args->cmd = SNDCTL_DSP_POST;
668 	return ioctl(p, (struct ioctl_args *)args, retval);
669 
670     case LINUX_SNDCTL_DSP_SUBDIVIDE:
671 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
672 	return ioctl(p, (struct ioctl_args *)args, retval);
673 
674     case LINUX_SNDCTL_DSP_SETFRAGMENT:
675 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
676 	return ioctl(p, (struct ioctl_args *)args, retval);
677 
678     case LINUX_SNDCTL_DSP_GETFMTS:
679 	args->cmd = SNDCTL_DSP_GETFMTS;
680 	return ioctl(p, (struct ioctl_args *)args, retval);
681 
682     case LINUX_SNDCTL_DSP_GETOSPACE:
683 	args->cmd = SNDCTL_DSP_GETOSPACE;
684 	return ioctl(p, (struct ioctl_args *)args, retval);
685 
686     case LINUX_SNDCTL_DSP_GETISPACE:
687 	args->cmd = SNDCTL_DSP_GETISPACE;
688 	return ioctl(p, (struct ioctl_args *)args, retval);
689 
690     case LINUX_SNDCTL_DSP_NONBLOCK:
691 	args->cmd = SNDCTL_DSP_NONBLOCK;
692 	return ioctl(p, (struct ioctl_args *)args, retval);
693 
694     case LINUX_TIOCGSERIAL:
695         linux_tiocgserial(fp, (struct linux_serial_struct *)args->arg);
696         return 0;
697 
698     case LINUX_TIOCSSERIAL:
699         linux_tiocsserial(fp, (struct linux_serial_struct *)args->arg);
700 	return 0;
701 
702     case LINUX_TCFLSH:
703       args->cmd = TIOCFLUSH;
704       switch (args->arg) {
705         case LINUX_TCIFLUSH:
706                 args->arg = FREAD;
707                 break;
708         case LINUX_TCOFLUSH:
709                 args->arg = FWRITE;
710                 break;
711         case LINUX_TCIOFLUSH:
712                 args->arg = FREAD | FWRITE;
713                 break;
714         default:
715 	        return EINVAL;
716       }
717       return ioctl(p, (struct ioctl_args *)args, retval);
718 
719     }
720     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
721 	    args->fd, (args->cmd&0xffff00)>>8,
722 	    (args->cmd&0xffff00)>>8, args->cmd&0xff);
723     return EINVAL;
724 }
725