/*
 *  linux/ibcs/ioctl.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Written by Drew Sullivan.
 */

#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 <asm/segment.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;
	int result = - EPERM;

	switch (class) {
	case 'T':			/* xenix ioctl compatibility */
		result = ibcs_ioctl_termio(fd, ioctl_num & 0xFF, arg);
		break;

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

	case 'C':
		result = ibcs_ioctl_console(fd, ioctl_num & 0xFF, arg);
		break;

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

	case 'l':
	case 'd':

	default:
		break;
	}
	if (result == - EPERM) {
		printk("iBCS2 ioctl(%d, %x[%s], %x) unsuported\n", fd, ioctl_num, fix(class), (int)arg);
	} else {
		printk("iBCS2 ioctl(%d, %x[%s], %x) == %d\n", fd, ioctl_num, fix(class), (int)arg, result);
	}
	return result;
}

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);
	}
	return - EPERM;
}

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  32: /* TCDSET  (TIOC|32) */
	case  33: /* RTS_TOG (TIOC|33) 386 - "RTS" toggle define 8A1 protocol */

	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 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 */
	}
	return - EPERM;
}

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;
	}
	return - EPERM;
}

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 :-) */
	}
	return - EPERM;
}
