/* $Id: ioctl.c,v 1.17 2002/02/08 03:57:14 davem Exp $
* ioctl.c: Solaris ioctl emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
*
* Streams & timod emulation based on code
* Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
*
* 1999-08-19 Implemented solaris 'm' (mag tape) and
* 'O' (openprom) ioctls, by Jason Rappleye
* (rappleye@ccr.buffalo.edu)
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/netdevice.h>
#include <linux/mtio.h>
#include <linux/time.h>
#include <linux/compat.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
#include <asm/openpromio.h>
#include "conv.h"
#include "socksys.h"
extern asmlinkage int compat_sys_ioctl(unsigned int fd, unsigned int cmd,
u32 arg);
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
extern int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
char __user *data_buf, int data_len, int flags);
extern int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, int __user *ctl_len,
char __user *data_buf, int data_maxlen, int __user *data_len, int *flags);
/* termio* stuff {{{ */
struct solaris_termios {
u32 c_iflag;
u32 c_oflag;
u32 c_cflag;
u32 c_lflag;
u8 c_cc[19];
};
struct solaris_termio {
u16 c_iflag;
u16 c_oflag;
u16 c_cflag;
u16 c_lflag;
s8 c_line;
u8 c_cc[8];
};
struct solaris_termiox {
u16 x_hflag;
u16 x_cflag;
u16 x_rflag[5];
u16 x_sflag;
};
static u32 solaris_to_linux_cflag(u32 cflag)
{
cflag &= 0x7fdff000;
if (cflag & 0x200000) {
int baud = cflag & 0xf;
cflag &= ~0x20000f;
switch (baud) {
case 0: baud = B57600; break;
case 1: baud = B76800; break;
case 2: baud = B115200; break;
case 3: baud = B153600; break;
case 4: baud = B230400; break;
case 5: baud = B307200; break;
case 6: baud = B460800; break;
}
cflag |= CBAUDEX | baud;
}
return cflag;
}
static u32 linux_to_solaris_cflag(u32 cflag)
{
cflag &= ~(CMSPAR | CIBAUD);
if (cflag & CBAUDEX) {
int baud = cflag & CBAUD;
cflag &= ~CBAUD;
switch (baud) {
case B57600: baud = 0; break;
case B76800: baud = 1; break;
case B115200: baud = 2; break;
case B153600: baud = 3; break;
case B230400: baud = 4; break;
case B307200: baud = 5; break;
case B460800: baud = 6; break;
case B614400: baud = 7; break;
case B921600: baud = 8; break;
#if 0
case B1843200: baud = 9; break;
#endif
}
cflag |= 0x200000 | baud;
}
return cflag;
}
static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg)
{
struct solaris_termio __user *p = A(arg);
int ret;
ret = sys_ioctl(fd, cmd, (unsigned long)p);
if (!ret) {
u32 cflag;
if (__get_user (cflag, &p->c_cflag))
return -EFAULT;
cflag = linux_to_solaris_cflag(cflag);
if (__put_user (cflag, &p->c_cflag))
return -EFAULT;
}
return ret;
}
static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg)
{
int ret;
struct solaris_termio s;
mm_segment_t old_fs = get_fs();
if (copy_from_user (&s, (struct solaris_termio __user *)A(arg), sizeof(struct solaris_termio)))
return -EFAULT;
s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, cmd, (unsigned long)&s);
set_fs(old_fs);
return ret;
}
static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg)
{
int ret;
struct solaris_termios s;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, cmd, (unsigned long)&s