/* $Id: timod.c,v 1.19 2002/02/08 03:57:14 davem Exp $
* timod.c: timod emulation.
*
* Copyright (C) 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)
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/netdevice.h>
#include <linux/poll.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
#include "conv.h"
#include "socksys.h"
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
static DEFINE_SPINLOCK(timod_pagelock);
static char * page = NULL ;
#ifndef DEBUG_SOLARIS_KMALLOC
#define mykmalloc kmalloc
#define mykfree kfree
#else
void * mykmalloc(size_t s, gfp_t gfp)
{
static char * page;
static size_t free;
void * r;
s = ((s + 63) & ~63);
if( s > PAGE_SIZE ) {
SOLD("too big size, calling real kmalloc");
return kmalloc(s, gfp);
}
if( s > free ) {
/* we are wasting memory, but we don't care */
page = (char *)__get_free_page(gfp);
free = PAGE_SIZE;
}
r = page;
page += s;
free -= s;
return r;
}
void mykfree(void *p)
{
}
#endif
#ifndef DEBUG_SOLARIS
#define BUF_SIZE PAGE_SIZE
#define PUT_MAGIC(a,m)
#define SCHECK_MAGIC(a,m)
#define BUF_OFFSET 0
#define MKCTL_TRAILER 0
#else
#define BUF_SIZE (PAGE_SIZE-2*sizeof(u64))
#define BUFPAGE_MAGIC 0xBADC0DEDDEADBABEL
#define MKCTL_MAGIC 0xDEADBABEBADC0DEDL
#define PUT_MAGIC(a,m) do{(*(u64*)(a))=(m);}while(0)
#define SCHECK_MAGIC(a,m) do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
__FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)
#define BUF_OFFSET sizeof(u64)
#define MKCTL_TRAILER sizeof(u64)
#endif
static char *getpage( void )
{
char *r;
SOLD("getting page");
spin_lock(&timod_pagelock);
if (page) {
r = page;
page = NULL;
spin_unlock(&timod_pagelock);
SOLD("got cached");
return r + BUF_OFFSET;
}
spin_unlock(&timod_pagelock);
SOLD("getting new");
r = (char *)__get_free_page(GFP_KERNEL);
PUT_MAGIC(r,BUFPAGE_MAGIC);
PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
return r + BUF_OFFSET;
}
static void putpage(char *p)
{
SOLD("putting page");
p = p - BUF_OFFSET;
SCHECK_MAGIC(p,BUFPAGE_MAGIC);
SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
spin_lock(&timod_pagelock);
if (page) {
spin_unlock(&timod_pagelock);
free_page((unsigned long)p);
SOLD("freed it");
} else {
page = p;
spin_unlock(&timod_pagelock);
SOLD("cached it");
}
}
static struct T_primsg *timod_mkctl(int size)
{
struct T_primsg *it;
SOLD("creating primsg");
it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
if (it) {
SOLD("got it");
it->pri = MSG_HIPRI;
it->length = size;
PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
}
return it;
}
static void timod_wake_socket(unsigned int fd)
{
struct socket *sock;
struct fdtable *fdt;
SOLD("wakeing socket");
fdt = files_fdtable(current->files);
sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode);
wake_up_interruptible(&sock->wait);
read_lock(&sock->sk->sk_callback_lock);
if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
__kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
read_unlock(&sock->sk->sk_callback_lock);
SOLD("done");
}
static void timod_queue(unsigned int fd, struct T_primsg *it)
{
struct sol_socket_struct *sock;
struct fdtable *fdt;
SOLD("queuing primsg");
fdt = files_fdtable(current->files);
sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data;
it