/*
 *  linux/ibcs/ioctl.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Writtin by Drew Sullivan.
 *
 * $Id: ioctl.c,v 1.1.1.2 1994/02/23 17:22:41 mike Exp $
 * $Source: /var/CVS/ibcs/ioctl.c,v $
 */
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/termios.h>
#include <linux/time.h>
#include <asm/segment.h>

#include <ibcs/ibcs.h>
#include <ibcs/trace.h>

static int ibcs_ioctl_termios(int fd, unsigned int func, void *arg);
static int ibcs_ioctl_termio(int fd, unsigned int func, void *arg);
static int ibcs_ioctl_console(int fd, unsigned int func, void *arg);
static int ibcs_ioctl_video(int fd, unsigned int func, void *arg);

static char *fix(int n) {
	static char char_class[4];
	
	 char_class[0] = n & 0xFF0000 ? (char)((n >> 16) & 0xFF) : '.';
	 char_class[1] = n & 0x00FF00 ? (char)((n >>  8) & 0xFF) : '.';
	 char_class[2] = n & 0x0000FF ? (char)((n      ) & 0xFF) : '.';
	 char_class[3] = 0;

	return char_class;
}

/* ibcs_ioctl is a meta mapper, that is
   it looks up the class of the ioctl and then
   dispatchs to lower level routines to handle the
   mapping of the actual ioctls
*/

#ifdef __cplusplus
extern "C" 
#endif

int ibcs_ioctl(int fd, unsigned int ioctl_num, void *arg) 
{
	unsigned int class = ioctl_num >> 8;

	switch (class) {
	case 'f':
		switch (ioctl_num & 0xff) {
			case 1: /* FIOCLEX */
				FD_SET(fd, &current->close_on_exec);
				return 0;
			case 2: /* FIONCLEX */
				FD_CLR(fd, &current->close_on_exec);
				return 0;
		}
		break;

	case 'T':			/* xenix ioctl compatibility */
		return ibcs_ioctl_termio(fd, ioctl_num & 0xFF, arg);

	case ('i' << 16) | ('X' << 8):	/* iBCS2 POSIX */
	case 'x':			/* Pre-iBCS2 POSIX */
		return ibcs_ioctl_termios(fd, ioctl_num & 0xFF, arg);

	case 'C':
		return ibcs_ioctl_console(fd, ioctl_num & 0xFF, arg);

	case ('i' << 16) | ('C' << 8):	/* iBCS2 POSIX */
	case 'X':
		return ibcs_ioctl_video(fd, ioctl_num & 0xFF, arg);

	case 'l':
	case 'd':

	default:
		switch (class & 0xff) {
			/* Wyse V/386 3.2.1A TCP/IP ioctls. */
			case 's':
			case 'r':
			case 'i':
				return wv386_ioctl(fd, ioctl_num, arg);

			/* SVR3 streams based socket TCP/IP ioctls.
			 * These are handed over to the standard ioctl
			 * handler since /dev/socksys is an emulated device
			 * and front ends any sockets created through it.
			 */
			case 'S':
			case 'R':
			case 'I':
				return sys_ioctl(fd, ioctl_num, arg);
		}
	}

	printk(KERN_ERR "iBCS: ioctl(%d, %x[%s], 0x%lx) unsupported\n",
		fd, ioctl_num, fix(class), (unsigned long)arg);
	return -EINVAL;
}

static int ibcs_ioctl_termios(int fd, unsigned int func, void *arg) {
	switch(func) {
	case 1:	/* XCGETA */	return sys_ioctl(fd, TCGETS, arg);
	case 2: /* XCSETA */	return sys_ioctl(fd, TCSETS, arg);
	case 3: /* XCSETAW */	return sys_ioctl(fd, TCSETSW, arg);
	case 4: /* XCSETAF */	return sys_ioctl(fd, TCSETSF, arg);
	}
	printk(KERN_ERR "iBCS: termios ioctl %d unsupported\n", func);
	return -EINVAL;
}

static int ibcs_ioctl_termio(int fd, unsigned int func, void *arg) {
	switch(func) {
		case 1: /* TCGETA  (TIOC|1) */
			return sys_ioctl(fd, TCGETA, arg);
		case 2: /* TCSETA  (TIOC|2) */
			return sys_ioctl(fd, TCSETA, arg);
		case 3: /* TCSETAW (TIOC|3) */
			return sys_ioctl(fd, TCSETAW, arg);
		case 4: /* TCSETAF (TIOC|4) */
			return sys_ioctl(fd, TCSETAF, arg);
		case 5: /* TCSBRK  (TIOC|5) */
			return sys_ioctl(fd, TCSBRK, arg);
		case 6: /* TCXONC  (TIOC|6) */
			return sys_ioctl(fd, TCXONC, arg);
		case 7: /* TCFLSH  (TIOC|7) */
			return sys_ioctl(fd, TCFLSH, arg);

		case  34: /* TCGETSC (TIOC|34) ioctl for scancodes */
			return 0x04; /* Translates scancode to ascii */
		case  35: /* TCSETSC (TIOC|35) ioctl for scancodes */
			return - EPERM;

		case 103: /* TIOCSWINSZ (TIOC|103) */
			return sys_ioctl(fd, TIOCSWINSZ, arg);
		case 104: /* TIOCGWINSZ (TIOC|104) */
			return sys_ioctl(fd, TIOCGWINSZ, arg);

		case  32: /* TCDSET  (TIOC|32) */
		case  33: /* RTS_TOG (TIOC|33) 386 - "RTS" toggle define 8A1 protocol */

		case 119: /* TIOCGPGRP  (TIOC|119) get pgrp of tty */
		case 118: /* TIOCSPGRP  (TIOC|118) set pgrp of tty */

		case 120: /* TIOSETSAK  (TIOC|120) set SAK sequence for tty */
		case 121: /* TIOGETSAK  (TIOC|121) get SAK sequence for tty */
			printk(KERN_ERR "iBCS: termio ioctl %d unimplemented\n",
				func);
			return -EINVAL;
	}
	printk(KERN_ERR "iBCS: termio ioctl %d unsupported\n", func);
	return -EINVAL;
}

static int ibcs_ioctl_console(int fd, unsigned int func, void *arg) {
	switch(func) {
		case 4: /* _TTYDEVTYPE */
			/* ***BUG*** if on console then 1, if pseudo tty
			 * then 2
			 */
			return 1;
	}
	printk(KERN_ERR "iBCS: console ioctl %d unsupported\n", func);
	return -EINVAL;
}

static int ibcs_ioctl_video(int fd, unsigned int func, void *arg) {
	switch(func) {
	case 4: /* C_IOC */
		/* get video memory map & IO privilege */
		/* see /etc/conf/pack.d/cn/class.h on any SCO unix box :-) */
	}
	printk(KERN_ERR "iBCS: video ioctl %d unsupported\n", func);
	return -EINVAL;
}
