diff options
author | Søren Schmidt <sos@FreeBSD.org> | 1995-06-25 17:32:43 +0000 |
---|---|---|
committer | Søren Schmidt <sos@FreeBSD.org> | 1995-06-25 17:32:43 +0000 |
commit | c21dee177fdd039bd54a169d52bad2c66942d766 (patch) | |
tree | a104b48d590fdc08acc1a23e9f4430c22923749e /sys/i386/linux/linux_ioctl.c | |
parent | 0f72d204e6f70d2f8aeaea290c70e1758420b245 (diff) | |
download | src-c21dee177fdd039bd54a169d52bad2c66942d766.tar.gz src-c21dee177fdd039bd54a169d52bad2c66942d766.zip |
First incarnation of our Linux emulator or rather compatibility code.
This first shot only incorporaties so much functionality that DOOM
can run (the X version), signal handling is VERY weak, so is many
other things. But it meets my milestone number one (you guessed it
- running DOOM).
Uses /compat/linux as prefix for loading shared libs, so it won't
conflict with our own libs.
Kernel must be compiled with "options COMPAT_LINUX" for this to work.
Notes
Notes:
svn path=/head/; revision=9313
Diffstat (limited to 'sys/i386/linux/linux_ioctl.c')
-rw-r--r-- | sys/i386/linux/linux_ioctl.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/sys/i386/linux/linux_ioctl.c b/sys/i386/linux/linux_ioctl.c new file mode 100644 index 000000000000..12adff4a18a8 --- /dev/null +++ b/sys/i386/linux/linux_ioctl.c @@ -0,0 +1,495 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: linux_ioctl.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/ioctl_compat.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/tty.h> +#include <sys/termios.h> +#include <machine/console.h> + + +struct linux_termios { + unsigned long c_iflag; + unsigned long c_oflag; + unsigned long c_cflag; + unsigned long c_lflag; + unsigned char c_line; + unsigned char c_cc[LINUX_NCCS]; +}; + +struct linux_winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + +static struct speedtab sptab[] = { + { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 }, + { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 }, + { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 }, + { 2400, 11 }, { 4800, 12 }, { 9600, 13 }, + { 19200, 14 }, { 38400, 15 }, + { 57600, 4097 }, { 115200, 4098 }, {-1, -1 } +}; + +static int +linux_to_bsd_speed(int code, struct speedtab *table) +{ + for ( ; table->sp_code != -1; table++) + if (table->sp_code == code) + return (table->sp_speed); + return -1; +} + +static int +bsd_to_linux_speed(int speed, struct speedtab *table) +{ + for ( ; table->sp_speed != -1; table++) + if (table->sp_speed == speed) + return (table->sp_code); + return -1; +} + +static void +bsd_to_linux_termios(struct termios *bsd_termios, + struct linux_termios *linux_termios) +{ + int i, speed; + +#ifdef DEBUG + printf("LINUX: BSD termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bsd_termios->c_cc[i]); + printf("\n"); +#endif + linux_termios->c_iflag = 0; + if (bsd_termios->c_iflag & IGNBRK) + linux_termios->c_iflag |= LINUX_IGNBRK; + if (bsd_termios->c_iflag & BRKINT) + linux_termios->c_iflag |= LINUX_BRKINT; + if (bsd_termios->c_iflag & IGNPAR) + linux_termios->c_iflag |= LINUX_IGNPAR; + if (bsd_termios->c_iflag & PARMRK) + linux_termios->c_iflag |= LINUX_PARMRK; + if (bsd_termios->c_iflag & INPCK) + linux_termios->c_iflag |= LINUX_INPCK; + if (bsd_termios->c_iflag & ISTRIP) + linux_termios->c_iflag |= LINUX_ISTRIP; + if (bsd_termios->c_iflag & INLCR) + linux_termios->c_iflag |= LINUX_INLCR; + if (bsd_termios->c_iflag & IGNCR) + linux_termios->c_iflag |= LINUX_IGNCR; + if (bsd_termios->c_iflag & ICRNL) + linux_termios->c_iflag |= LINUX_ICRNL; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXANY; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXON; + if (bsd_termios->c_iflag & IXOFF) + linux_termios->c_iflag |= LINUX_IXOFF; + if (bsd_termios->c_iflag & IMAXBEL) + linux_termios->c_iflag |= LINUX_IMAXBEL; + + linux_termios->c_oflag = 0; + if (bsd_termios->c_oflag & OPOST) + linux_termios->c_oflag |= LINUX_OPOST; + if (bsd_termios->c_oflag & ONLCR) + linux_termios->c_oflag |= LINUX_ONLCR; + if (bsd_termios->c_oflag & OXTABS) + linux_termios->c_oflag |= LINUX_XTABS; + + linux_termios->c_cflag = + bsd_to_linux_speed(bsd_termios->c_ispeed, sptab); + linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4; + if (bsd_termios->c_cflag & CSTOPB) + linux_termios->c_cflag |= LINUX_CSTOPB; + if (bsd_termios->c_cflag & CREAD) + linux_termios->c_cflag |= LINUX_CREAD; + if (bsd_termios->c_cflag & PARENB) + linux_termios->c_cflag |= LINUX_PARENB; + if (bsd_termios->c_cflag & PARODD) + linux_termios->c_cflag |= LINUX_PARODD; + if (bsd_termios->c_cflag & HUPCL) + linux_termios->c_cflag |= LINUX_HUPCL; + if (bsd_termios->c_cflag & CLOCAL) + linux_termios->c_cflag |= LINUX_CLOCAL; + if (bsd_termios->c_cflag & CRTSCTS) + linux_termios->c_cflag |= LINUX_CRTSCTS; + + linux_termios->c_lflag = 0; + if (bsd_termios->c_lflag & ISIG) + linux_termios->c_lflag |= LINUX_ISIG; + if (bsd_termios->c_lflag & ICANON) + linux_termios->c_lflag |= LINUX_ICANON; + if (bsd_termios->c_lflag & ECHO) + linux_termios->c_lflag |= LINUX_ECHO; + if (bsd_termios->c_lflag & ECHOE) + linux_termios->c_lflag |= LINUX_ECHOE; + if (bsd_termios->c_lflag & ECHOK) + linux_termios->c_lflag |= LINUX_ECHOK; + if (bsd_termios->c_lflag & ECHONL) + linux_termios->c_lflag |= LINUX_ECHONL; + if (bsd_termios->c_lflag & NOFLSH) + linux_termios->c_lflag |= LINUX_NOFLSH; + if (bsd_termios->c_lflag & TOSTOP) + linux_termios->c_lflag |= LINUX_TOSTOP; + if (bsd_termios->c_lflag & ECHOCTL) + linux_termios->c_lflag |= LINUX_ECHOCTL; + if (bsd_termios->c_lflag & ECHOPRT) + linux_termios->c_lflag |= LINUX_ECHOPRT; + if (bsd_termios->c_lflag & ECHOKE) + linux_termios->c_lflag |= LINUX_ECHOKE; + if (bsd_termios->c_lflag & FLUSHO) + linux_termios->c_lflag |= LINUX_FLUSHO; + if (bsd_termios->c_lflag & PENDIN) + linux_termios->c_lflag |= LINUX_PENDIN; + if (bsd_termios->c_lflag & IEXTEN) + linux_termios->c_lflag |= LINUX_IEXTEN; + + for (i=0; i<LINUX_NCCS; i++) + linux_termios->c_cc[i] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR]; + linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT]; + linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE]; + linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL]; + linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF]; + linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL]; + linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN]; + linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME]; + linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2]; + linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP]; + linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART]; + linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP]; + linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT]; + linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD]; + linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE]; + linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT]; + + linux_termios->c_line = 0; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", linux_termios->c_cc[i]); + printf("\n"); +#endif +} + +static void +linux_to_bsd_termios(struct linux_termios *linux_termios, + struct termios *bsd_termios) +{ + int i, speed; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", linux_termios->c_cc[i]); + printf("\n"); +#endif + bsd_termios->c_iflag = 0; + if (linux_termios->c_iflag & LINUX_IGNBRK) + bsd_termios->c_iflag |= IGNBRK; + if (linux_termios->c_iflag & LINUX_BRKINT) + bsd_termios->c_iflag |= BRKINT; + if (linux_termios->c_iflag & LINUX_IGNPAR) + bsd_termios->c_iflag |= IGNPAR; + if (linux_termios->c_iflag & LINUX_PARMRK) + bsd_termios->c_iflag |= PARMRK; + if (linux_termios->c_iflag & LINUX_INPCK) + bsd_termios->c_iflag |= INPCK; + if (linux_termios->c_iflag & LINUX_ISTRIP) + bsd_termios->c_iflag |= ISTRIP; + if (linux_termios->c_iflag & LINUX_INLCR) + bsd_termios->c_iflag |= INLCR; + if (linux_termios->c_iflag & LINUX_IGNCR) + bsd_termios->c_iflag |= IGNCR; + if (linux_termios->c_iflag & LINUX_ICRNL) + bsd_termios->c_iflag |= ICRNL; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXANY; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXON; + if (linux_termios->c_iflag & LINUX_IXOFF) + bsd_termios->c_iflag |= IXOFF; + if (linux_termios->c_iflag & LINUX_IMAXBEL) + bsd_termios->c_iflag |= IMAXBEL; + + bsd_termios->c_oflag = 0; + if (linux_termios->c_oflag & LINUX_OPOST) + bsd_termios->c_oflag |= OPOST; + if (linux_termios->c_oflag & LINUX_ONLCR) + bsd_termios->c_oflag |= ONLCR; + if (linux_termios->c_oflag & LINUX_XTABS) + bsd_termios->c_oflag |= OXTABS; + + bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4; + if (linux_termios->c_cflag & LINUX_CSTOPB) + bsd_termios->c_cflag |= CSTOPB; + if (linux_termios->c_cflag & LINUX_PARENB) + bsd_termios->c_cflag |= PARENB; + if (linux_termios->c_cflag & LINUX_PARODD) + bsd_termios->c_cflag |= PARODD; + if (linux_termios->c_cflag & LINUX_HUPCL) + bsd_termios->c_cflag |= HUPCL; + if (linux_termios->c_cflag & LINUX_CLOCAL) + bsd_termios->c_cflag |= CLOCAL; + if (linux_termios->c_cflag & LINUX_CRTSCTS) + bsd_termios->c_cflag |= CRTSCTS; + + bsd_termios->c_lflag = 0; + if (linux_termios->c_lflag & LINUX_ISIG) + bsd_termios->c_lflag |= ISIG; + if (linux_termios->c_lflag & LINUX_ICANON) + bsd_termios->c_lflag |= ICANON; + if (linux_termios->c_lflag & LINUX_ECHO) + bsd_termios->c_lflag |= ECHO; + if (linux_termios->c_lflag & LINUX_ECHOE) + bsd_termios->c_lflag |= ECHOE; + if (linux_termios->c_lflag & LINUX_ECHOK) + bsd_termios->c_lflag |= ECHOK; + if (linux_termios->c_lflag & LINUX_ECHONL) + bsd_termios->c_lflag |= ECHONL; + if (linux_termios->c_lflag & LINUX_NOFLSH) + bsd_termios->c_lflag |= NOFLSH; + if (linux_termios->c_lflag & LINUX_TOSTOP) + bsd_termios->c_lflag |= TOSTOP; + if (linux_termios->c_lflag & LINUX_ECHOCTL) + bsd_termios->c_lflag |= ECHOCTL; + if (linux_termios->c_lflag & LINUX_ECHOPRT) + bsd_termios->c_lflag |= ECHOPRT; + if (linux_termios->c_lflag & LINUX_ECHOKE) + bsd_termios->c_lflag |= ECHOKE; + if (linux_termios->c_lflag & LINUX_FLUSHO) + bsd_termios->c_lflag |= FLUSHO; + if (linux_termios->c_lflag & LINUX_PENDIN) + bsd_termios->c_lflag |= PENDIN; + if (linux_termios->c_lflag & IEXTEN) + bsd_termios->c_lflag |= IEXTEN; + + for (i=0; i<NCCS; i++) + bsd_termios->c_cc[i] = _POSIX_VDISABLE; + bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR]; + bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT]; + bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE]; + bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL]; + bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF]; + bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL]; + bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN]; + bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME]; + bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2]; + bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP]; + bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART]; + bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP]; + bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT]; + bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD]; + bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE]; + bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT]; + + bsd_termios->c_ispeed = bsd_termios->c_ospeed = + linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab); +#ifdef DEBUG + printf("LINUX: BSD termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bsd_termios->c_cc[i]); + printf("\n"); +#endif +} + + +struct linux_ioctl_args { + int fd; + int cmd; + int arg; +}; + +int +linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval) +{ + struct termios bsd_termios; + struct winsize bsd_winsize; + struct linux_termios linux_termios; + struct linux_winsize linux_winsize; + struct filedesc *fdp = p->p_fd; + struct file *fp; + int (*func)(); + int bsd_line, linux_line; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): ioctl(%d, %04x, *)\n", + p->p_pid, args->fd, args->cmd); +#endif + if ((unsigned)args->fd >= fdp->fd_nfiles + || (fp = fdp->fd_ofiles[args->fd]) == 0) + return EBADF; + + if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) { + return EBADF; + } + + func = fp->f_ops->fo_ioctl; + switch (args->cmd) { + case LINUX_TCGETS: + if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0) + return error; + bsd_to_linux_termios(&bsd_termios, &linux_termios); + return copyout((caddr_t)&linux_termios, (caddr_t)args->arg, + sizeof(linux_termios)); + + case LINUX_TCSETS: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSW: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSF: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p); + + case LINUX_TIOCGPGRP: + args->cmd = TIOCGPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCSPGRP: + args->cmd = TIOCSPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCGWINSZ: + args->cmd = TIOCGWINSZ; + return ioctl(p, args, retval); + + case LINUX_TIOCSWINSZ: + args->cmd = TIOCSWINSZ; + return ioctl(p, args, retval); + + case LINUX_FIONREAD: + args->cmd = FIONREAD; + return ioctl(p, args, retval); + + case LINUX_FIONBIO: + args->cmd = FIONBIO; + return ioctl(p, args, retval); + + case LINUX_FIOASYNC: + args->cmd = FIOASYNC; + return ioctl(p, args, retval); + + case LINUX_FIONCLEX: + args->cmd = FIONCLEX; + return ioctl(p, args, retval); + + case LINUX_FIOCLEX: + args->cmd = FIOCLEX; + return ioctl(p, args, retval); + + case LINUX_TIOCEXCL: + args->cmd = TIOCEXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCNXCL: + args->cmd = TIOCNXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCCONS: + args->cmd = TIOCCONS; + return ioctl(p, args, retval); + + case LINUX_TIOCNOTTY: + args->cmd = TIOCNOTTY; + return ioctl(p, args, retval); + + case LINUX_TIOCSETD: + switch (args->arg) { + case LINUX_N_TTY: + bsd_line = TTYDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_SLIP: + bsd_line = SLIPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_PPP: + bsd_line = PPPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + default: + return EINVAL; + } + break; + + case LINUX_TIOCGETD: + bsd_line = TTYDISC; + if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p)) + return error; + switch (bsd_line) { + case TTYDISC: + linux_line = LINUX_N_TTY; + break; + case SLIPDISC: + linux_line = LINUX_N_SLIP; + break; + case PPPDISC: + linux_line = LINUX_N_PPP; + break; + default: + return EINVAL; + } + return copyout(&linux_line, (caddr_t)args->arg, + sizeof(int)); + } + uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n", + args->fd, (args->cmd&0xffff00)>>8, + (args->cmd&0xffff00)>>8, args->cmd&0xff); + return EINVAL; +} |