#ifndef __QNXNTO__

#include "driver.h"
#include "qnx4_proc.h"

/* globals */

pid_t parent;

static struct device 	snd_devices[MAX_DEVICES];
static snd_ocb_t	*ocb_list[MAX_OPEN_FILES];
static void 		*fd_ctrl;
static int		major;
static int		minor = 1;
static time_t __far	*timeptr;

static struct  _sysmsg_version_reply version = {
                NAME,
                __DATE__,
                VERSION,
                RELEASE,
                0
		};

/* private func decls */
static int snd_open(int minor, pid_t pid, caddr_t msg);
static int snd_dup(int minor, pid_t pid, caddr_t msg);
static int snd_handle(int minor, pid_t pid, caddr_t msg);
static int snd_stat(int minor, pid_t pid, caddr_t m);
static int snd_flags(int minor, pid_t pid, caddr_t msg);
static int snd_chown(int minor, pid_t pid, caddr_t msg);
static int snd_chmod(int minor, pid_t pid, caddr_t msg);
static int snd_read(int minor, pid_t pid, caddr_t msg);
static int snd_ioctl(int minor, pid_t pid, caddr_t msg);
static int snd_write(int minor, pid_t pid, caddr_t msg);
static int snd_select(int minor, pid_t pid, caddr_t msg);
static int snd_close(int minor, pid_t pid, caddr_t msg);
static int chk_perm(uid_t u, gid_t g, mode_t io_mode, iofunc_attr_t *obj);
static void ids(pid_t pid, uid_t *u, gid_t *g);
static void iofunc_attr_init(iofunc_attr_t *attr, mode_t mode);
static short int set_file_flags(short int ioflag);
static int ocb_attach(pid_t pid, short int fd, snd_ocb_t *ocb);
static int register_device(snd_attr_t *snd_attr, char *dev_name);
static void signal_handler(int);


/* public funcs */

/* this function should really return a status */

void 
snd_sound_init(void)
{
	struct _osinfo info;

	parent = getpid();

	if (qnx_osinfo(0, &info) < 0) {
		perror("qnx_osinfo");
		return;
	}

	timeptr = MK_FP(info.timesel, offsetof(struct _timesel, seconds));

	/* initialize the timing loop */
	initloop(&info);

        if ((major = qnx_device_attach()) < 0) {
                perror("qnx_device_attach");
                return;
        }
}

void 
snd_sound_cleanup(void)
{
}

snd_attr_t *
snd_register_io(void *data, char *name, snd_io_t *io)
{

	snd_attr_t		*snd_attr;
	char 			*dev_name;

	if ((snd_attr =	 snd_calloc(sizeof(snd_attr_t))) == NULL)
                return NULL;
        
        if ((dev_name = snd_malloc(strlen(name) + strlen("/dev/") + 1)) == NULL ) {
                snd_free(snd_attr, sizeof(snd_attr_t));
                return NULL;
        }
        strcpy(dev_name, "/dev/");
        strcat(dev_name, name);

        snd_attr->id = minor;
        snd_attr->data = data;
        snd_attr->io = *io;
        snd_attr->attr.minor = minor;
        snd_attr->attr.major = major;
        minor++;

	if (register_device(snd_attr, dev_name) < 0) {
                snd_free(snd_attr, sizeof(snd_attr_t));
                return NULL;
        }

        return (snd_attr);
}

void
snd_unregister_io(snd_attr_t *attr)
{
	int i;

	for (i = 0; i < MAX_DEVICES; i++) {
                if (snd_devices[i].attr && snd_devices[i].attr->id == attr->id)
                        break;
        }
	if (i < MAX_DEVICES) {

                qnx_prefix_detach(snd_devices[i].pfx);
                snd_free_str(snd_devices[i].pfx);
                snd_free(snd_devices[i].attr, sizeof(snd_attr_t));
                snd_devices[i].pfx = "";
                snd_devices[i].attr = NULL;
        }
}

int 
snd_start(void)
{
	pid_t			pid;
        message_t		msg;
	struct _mxfer_entry	rmx[2];
        setbuf(stdout, NULL);

        if ((fd_ctrl = __init_fd(getpid())) == NULL) {
                perror("__init_fd");
                return (-1);
        }

	qnx_pflags(_PPF_SERVER | _PPF_PRIORITY_FLOAT | _PPF_SIGCATCH |
                   _PPF_IMMORTAL, 
                   _PPF_SERVER | _PPF_PRIORITY_FLOAT | _PPF_SIGCATCH |
                   _PPF_IMMORTAL, NULL, NULL);

	setup_signal_handling(signal_handler);
	
	kconf(4, 1024);

	for(;;resched()) {

                pid = Receive(0, &msg, sizeof(msg));

                if (pid < 0) {
                        perror("Receive");
                        continue;
                }

                if (chk_pid(pid))
                        continue;

                switch(msg.type) {

		case _SYSMSG:
                        if (msg.sysmsg.subtype == _SYSMSG_SUBTYPE_VERSION) {

                                msg.sysmsg_reply.status = EOK;
                                _setmx(&rmx[0], &msg.sysmsg_reply, 
                                       sizeof(msg.sysmsg_reply));

                                _setmx(&rmx[1], &version, sizeof(version));
                                Replymx(pid, 2, rmx);
                                continue;
                        }
                        break;

		case _DEV_INFO:

			msg.status = ENOSYS;
			break;
/* disabled for now
			if (pcreat( snd_fdinfo, 1, pid, (caddr_t) &msg) < 0) {
				msg.fdinfo_reply.status = EAGAIN;
				break;
			}
			continue;
*/

                case _IO_OPEN:

			if (pcreat(snd_open, 1, pid, (caddr_t) &msg) < 0) {
				msg.open_reply.status = EAGAIN;
                                break;
			}
			continue;

                case _IO_DUP:

			if (pcreat(snd_dup, 1, pid, (caddr_t) &msg) < 0) {
				msg.dup_reply.status = EAGAIN;
                                break;
			}
			continue;
                        
                case _IO_CLOSE:

			if (pcreat(snd_close, 1, pid, (caddr_t) &msg) < 0) {
				msg.close_reply.status = EAGAIN;
                                break;
			}
			continue;

                case _IO_HANDLE:

                        if (pcreat(snd_handle, 1, pid, (caddr_t) &msg) < 0) {
				msg.open_reply.status = EAGAIN;
                                break;
			}
			continue;

		case _IO_FLAGS:
			
			if (pcreat(snd_flags, 1, pid, (caddr_t) &msg) < 0) {
				msg.flags_reply.status = EAGAIN;
				break;
			}
			continue;

                case _IO_CHOWN:

			if (pcreat(snd_chown, 1, pid, (caddr_t) &msg) < 0) {
				msg.chown_reply.status = EAGAIN;
				break;
			}
			continue;

                case _IO_CHMOD:
                        
                        if (pcreat(snd_chmod, 1, pid, (caddr_t) &msg) < 0) {
                                msg.chmod_reply.status = EAGAIN;
                                break;
                        }
                        continue;

                case _IO_READ:

                        if (pcreat(snd_read, 1, pid, (caddr_t) &msg) < 0) {
                                msg.read_reply.status = EAGAIN;
                                break;
                        }
                            
                        continue;

                case _IO_WRITE:

                        if (pcreat(snd_write, 1, pid, (caddr_t) &msg) < 0) {
                                msg.write_reply.status = EAGAIN;
                                break;
                        }
                        continue;
                        
                case _IO_STAT:

                        if (pcreat(snd_stat, 1, pid, (caddr_t) &msg) < 0) {
				msg.stat_reply.status = EAGAIN;
                                break;
			}
			continue;

                case _IO_IOCTL:
                case _IO_QIOCTL:

			if (pcreat(snd_ioctl, 1, pid, (caddr_t) &msg) < 0) {
				msg.ioctl_reply.status = EAGAIN;
                                break;
			}
			continue;
                        
                case _IO_SELECT:
			
			if (pcreat(snd_select, 1, pid, (caddr_t) &msg) < 0) {
				msg.select_reply.status = EAGAIN;
				break;
			}
			continue;

		case _IO_UTIME:
			
			msg.status = ENOSYS;
			break;
/* disabled for now
			if (pcreat( snd_utime, 1, pid, (caddr_t) &msg) < 0) {
				msg.utime_reply.status = EAGAIN;
				break;
			}
			continue;
*/
		case _IO_LSEEK:
			msg.status = ENOTBLK;
			break;

		case _IO_CHDIR:
		case _IO_READDIR:
		case _IO_REWINDDIR:
			msg.status = ENOTDIR;
			break;			

                default:
                        msg.status = ENOSYS;
                        break;
                }

                if (Reply(pid, &msg, sizeof(msg)) < 0)
                        perror("Reply");
        }
}


int 
snd_ioctl_out( long *arg, long value)
{
	*arg = value;
	return sizeof( long );
}


long 
snd_ioctl_in( long *arg )
{
	return *arg;
}


void 
snd_notify_trigger(snd_ocb_t *ocb, int n, int ndx)
{
	if (ndx & NOTIFY_INPUT) {
                if (ocb->notify[0].proxy) {
                        ocb->notify[0].set.flag |= _SEL_IS_INPUT;
			Trigger( ocb->notify[0].proxy );
                }
        }
	if(ndx & NOTIFY_OUTPUT) {
                if (ocb->notify[1].proxy) {
                        ocb->notify[1].set.flag |= _SEL_IS_OUTPUT;
			Trigger( ocb->notify[1].proxy );
                }
        }
	if(ndx & NOTIFY_EXCEPT) {
                if (ocb->notify[2].proxy) {
                        ocb->notify[2].set.flag |= _SEL_IS_EXCEPT;
			Trigger( ocb->notify[2].proxy );
                }
        }
}


int 
snd_copy_to_user(snd_context_t *ctp, void *buffer, int nbytes)
{
        struct _mxfer_entry mx;

        _setmx(&mx, buffer, nbytes);
        return (ctp->rw_offset += Writemsgmx(ctp->pid, ctp->rw_offset, 1, &mx));
}

int 
snd_copy_from_user(snd_context_t *ctp, void *buffer, int nbytes)
{
        int rval;
        struct _mxfer_entry mx;

        _setmx(&mx, buffer, nbytes);
        rval = Readmsgmx(ctp->pid, ctp->rw_offset, 1, &mx);
        return (ctp->rw_offset += rval);
}

/* iomgr funcs */

static int
snd_open(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*attr;
	snd_ocb_t		*ocb;
	snd_open_t		*ptr;
	struct _io_open		*open;
	struct _io_open_reply	*reply;
	int			i, ret;
        uid_t uid;
        gid_t gid;

        open = (struct _io_open *) msg;
        reply = (struct _io_open_reply *) msg;

        ids(pid, &uid, &gid);

        for (i = 0; i < MAX_DEVICES; i++) {
                if (snd_devices[i].attr && snd_devices[i].attr->id == open->unit)
                        break;
        }
        assert(i < MAX_DEVICES);
        attr = snd_devices[i].attr;

        if ((ocb = snd_calloc(sizeof(snd_ocb_t))) == NULL) {

		snd_printk("couldn't allocate %d bytes\n", sizeof (iofunc_ocb_t));
                reply->status = ENOMEM;
                goto reply;
	}

        ocb->iofunc_ocb.attr = attr;
        ocb->iofunc_ocb.oflag = open->oflag;
	ocb->iofunc_ocb.ioflag = set_file_flags(open->oflag);

        ret = chk_perm(uid, gid, ocb->iofunc_ocb.ioflag, &attr->attr);
        if (ret != EOK) {
                reply->status = ret;
                goto reply;
        }

        if ((ptr = attr->io.open) == NULL) {
		if( !attr->attr.ino_nlink )
                	snd_free(ocb, sizeof(snd_ocb_t));
                reply->status = ENXIO;
                goto reply;
        }

        if ((ret = ptr(attr->data, ocb)) < 0) {
		if( !attr->attr.ino_nlink )
                	snd_free(ocb, sizeof(snd_ocb_t));
                reply->status = (-ret);
                goto reply;
        }

        if (ocb_attach(pid, open->fd, ocb) < 0) {
		if( !attr->attr.ino_nlink )
                	snd_free(ocb, sizeof(snd_ocb_t));
                reply->status = errno;
                goto reply;
        }
        
	attr->attr.ino_nlink++;
        reply->status = EOK;

 reply:
	attr->attr.ino_atime = attr->attr.ino_atime = 
	  attr->attr.ino_ctime = *timeptr;
        Reply(pid, reply, sizeof(*reply));

        return (0);
}


static int
snd_dup(int minor, pid_t pid, caddr_t msg)
{

        struct _io_dup		*dup;
	struct _io_dup_reply	*reply;
	snd_ocb_t		*ocb;
        snd_attr_t		*attr;

	dup = (struct _io_dup *) msg;
	reply = (struct _io_dup_reply *) msg;

	ocb = ocb_list[__get_fd(dup->src_pid, dup->src_fd, fd_ctrl)];

	attr = ocb->iofunc_ocb.attr;

        if (ocb_attach(dup->src_pid, dup->dst_fd, ocb) < 0) {
                reply->status = errno;
                goto reply;
        }

	attr->attr.ino_nlink++;
        reply->status = EOK;

 reply:
        Reply(pid, reply, sizeof(*reply));

        return (0);

}

static int
snd_handle(int minor, pid_t pid, caddr_t msg)
{
        struct _io_open 		*open;
        struct _io_open_reply 		*reply;
	int				i;
        snd_attr_t			*attr;
	snd_ocb_t			*ocb;
        
        open = (struct _io_open *) msg;
        reply = (struct _io_open_reply *) msg;

        for (i = 0; i < MAX_DEVICES; i++) {
                if (snd_devices[i].attr && snd_devices[i].attr->id == open->unit)
                        break;
        }
        assert(i < MAX_DEVICES);
        attr = snd_devices[i].attr;

        if ((ocb = snd_calloc(sizeof(snd_ocb_t))) == NULL) {

		snd_printk("couldn't allocate %d bytes\n", sizeof (iofunc_ocb_t));
                reply->status = ENOMEM;
                goto reply;
	}
        ocb->iofunc_ocb.attr = attr;

        /* check perms, etc here */

        ocb->iofunc_ocb.oflag = open->oflag;
	ocb->iofunc_ocb.ioflag = set_file_flags(open->oflag);
        
        if (ocb_attach(pid, open->fd, ocb) < 0) {
		if( !attr->attr.ino_nlink )
                	snd_free(ocb, sizeof(snd_ocb_t));
                reply->status = errno;
                goto reply;
        }
        
	/* should we increase the nlink? Will snd_close() ever be called for this? */
	attr->attr.ino_nlink++;
        reply->status = EOK;

reply:        
        Reply(pid, reply, sizeof(*reply));
        return 0;
}


static int
snd_stat(int minor, pid_t pid, caddr_t m)
{
	snd_attr_t		*snd_attr;
        iofunc_attr_t 		*attr;
        int			i;
        struct _io_fstat	*stat;
	struct _io_fstat_reply	*reply;
        message_t 		*msg;

	msg = (message_t *) m;
	stat = (struct _io_fstat *) m;
        reply = (struct _io_fstat_reply *) m;

        for (i = 0; i < MAX_DEVICES; i++) {
                if (snd_devices[i].attr && snd_devices[i].attr->id == msg->open.unit)
                        break;
        }
        assert(i < MAX_DEVICES);
        snd_attr = snd_devices[i].attr;
        attr = &snd_attr->attr;
        
        msg->stat_reply.stat.st_mode = attr->ino_ftype;
        msg->stat_reply.stat.st_ino = attr->ino_ino;
        msg->stat_reply.stat.st_dev = attr->ino_dev;
        msg->stat_reply.stat.st_rdev = attr->ino_rdev;
        msg->stat_reply.stat.st_nlink = attr->ino_nlink;
        msg->stat_reply.stat.st_uid = msg->stat_reply.stat.st_ouid = attr->ino_uid;
        msg->stat_reply.stat.st_gid = msg->stat_reply.stat.st_ogid = attr->ino_gid;
        msg->stat_reply.stat.st_size = attr->ino_size;
        msg->stat_reply.stat.st_atime = attr->ino_atime;
        msg->stat_reply.stat.st_mtime = attr->ino_mtime;
        msg->stat_reply.stat.st_ctime = attr->ino_ctime;

        reply->status = EOK;
	Reply(pid, reply, sizeof(*reply));
	return (0);
}


static int 
snd_flags(int minor, pid_t pid, caddr_t msg)
{
	struct _io_flags	*flags;
	struct _io_flags_reply	*reply;	
	snd_ocb_t		*ocb;

        flags = (struct _io_flags *) msg;
        reply = (struct _io_flags_reply *) msg;

	ocb = ocb_list[__get_fd(pid, flags->fd, fd_ctrl)];

	if( flags->mask ) {
		ocb->iofunc_ocb.oflag = flags->bits & flags->mask;
        	ocb->iofunc_ocb.ioflag = 
	                set_file_flags(ocb->iofunc_ocb.oflag );
	}

        reply->status = EOK;
	reply->flags = ocb->iofunc_ocb.oflag;

        Reply(pid, reply, sizeof(*reply));
	return(0);
}


static int
snd_chown(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*snd_attr;
	snd_ocb_t		*snd_ocb;
	iofunc_attr_t		*attr;
	struct _io_chown	*chown;
	struct _io_chown_reply	*reply;
	uid_t			uuid, uid;
	gid_t			ugid, gid;
        
        chown = (struct _io_chown *) msg;
        reply = (struct _io_chown_reply *) msg;

        snd_ocb = ocb_list[__get_fd(pid, chown->fd, fd_ctrl)];
	snd_attr = snd_ocb->iofunc_ocb.attr;
	attr = &snd_attr->attr;

        uid = chown->uid;
        gid = chown->gid;
        
        ids(pid, &uuid, &ugid);
        if (attr->ino_uid != uid && uuid != 0) {
                reply->status = EPERM;
                goto reply;
        }
        if (attr->ino_gid != gid && gid != ugid && uuid!=0) {
                reply->status = EPERM;
                goto reply;
        }

        attr->ino_uid = uid;
        attr->ino_gid = gid;
	attr->ino_ctime = *timeptr;
        reply->status = EOK;

 reply:
        Reply(pid, reply, sizeof(*reply));
        return (0);
}


static int
snd_chmod(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*snd_attr;
	snd_ocb_t		*snd_ocb;
	iofunc_attr_t		*attr;
	struct _io_chmod	*chmod;
	struct _io_chmod_reply	*reply;
	uid_t			uuid;
	gid_t			ugid;
        
        chmod = (struct _io_chmod *) msg;
        reply = (struct _io_chmod_reply *) msg;

        snd_ocb = ocb_list[__get_fd(pid, chmod->fd, fd_ctrl)];
	snd_attr = snd_ocb->iofunc_ocb.attr;
	attr = &snd_attr->attr;

        ids(pid, &uuid, &ugid);
        if (uuid != attr->ino_uid && uuid != 0) {
                reply->status = EPERM;
                goto reply;
        }

        attr->ino_ftype &= ~07777;
        attr->ino_ftype |= chmod->mode & 07777;
	attr->ino_ctime = *timeptr;
        reply->status = EOK;

 reply:
        Reply(pid, reply, sizeof(*reply));
        return (0);
}


static int 
snd_read(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*snd_attr;
	snd_read_t		*ptr;
	snd_context_t		snd_ctx;
	int			nbytes;
        struct _io_read		*read;
	struct _io_read_reply	*reply;

	read = (struct _io_read *) msg;
	reply = (struct _io_read_reply *) msg;

	snd_ctx.ocb = ocb_list[__get_fd(pid, read->fd, fd_ctrl)];
	snd_attr = snd_ctx.ocb->iofunc_ocb.attr;

        if ((ptr = snd_attr->io.read) == NULL) {
                reply->status = ENXIO;
                reply->nbytes = 0;
                goto reply;
        }

        snd_ctx.pid = pid;
        snd_ctx.nonblock = (snd_ctx.ocb->iofunc_ocb.ioflag & _IO_FLAG_NONBLOCK);
        snd_ctx.rw_offset = sizeof(struct _io_write) - sizeof(char[1]);

        if ((nbytes = ptr(&snd_ctx, read->nbytes)) >= 0) {
                reply->nbytes = nbytes;
                reply->status = EOK;
                goto reply;
        }

        reply->status = -nbytes;
        reply->nbytes = 0;

 reply:
	snd_attr->attr.ino_atime = *timeptr;
        Reply(pid, reply, sizeof(*reply));

        return (0);
}


static int
snd_ioctl(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*snd_attr;
	snd_ocb_t		*ocb;
        snd_ioctl_t		*ptr;
        long 			dcmd;
	char 			*buffer;
	struct _mxfer_entry	mx[2];
	int			error = EOK, nbytes;
        struct _io_qioctl	*ioctl;
        struct _io_qioctl_reply *reply;

        ioctl = (struct _io_qioctl *) msg;
        reply = (struct _io_qioctl_reply *) msg;

	ocb = ocb_list[__get_fd(pid, ioctl->fd, fd_ctrl)];
	snd_attr = ocb->iofunc_ocb.attr;

        if ((ptr = snd_attr->io.ioctl) == NULL) {
                reply->status = ENXIO;
                goto reply;
        }

        /* sneaky! but how else can we get the direction */
        dcmd = ioctl->zero;

        if (!((dcmd & IOC_DIRMASK) & IOC_INOUT))
                nbytes = 0, buffer = NULL;

        else {

                nbytes = ioctl->nbytes;
                if ((buffer = snd_malloc(nbytes)) == NULL) {
                        reply->status = ENOMEM;
                        goto reply;
                }

                if ((dcmd & IOC_DIRMASK) & IOC_IN) {

                        if (Readmsg(pid, offsetof(struct _io_qioctl, data),
                                (void *) buffer, nbytes) == -1) {
                                snd_free(buffer, nbytes);
                                reply->status = errno;
                                goto reply;
                        }
			snd_attr->attr.ino_mtime = *timeptr;
                }
        }

	if ((nbytes = ptr(ocb, dcmd, (long)buffer, nbytes )) < 0 )
		error = -nbytes;

        reply->ret_val = nbytes;
        reply->status = error;
	snd_attr->attr.ino_atime = *timeptr;

        if (error == EOK && (dcmd & IOC_DIRMASK) & IOC_OUT)  {

                _setmx(&mx[0], reply, sizeof(struct _io_qioctl_reply) - 
                       sizeof(char[1]));
                _setmx(&mx[1], buffer, nbytes);
                if (Replymx(pid, 2, &mx) < 0) 
                        perror("Replymx");
                return (0);
        }

 reply:
        if (Reply(pid, reply, sizeof(struct _io_qioctl_reply)) < 0)
                perror("Reply");

        snd_free(buffer, nbytes);

        return (0);
}

 
#define MAX_WRITE_SIZE 0x7fff	// max positive signed short
static int
snd_write(int minor, pid_t pid, caddr_t msg)
{
	snd_attr_t		*snd_attr;
	snd_write_t		*ptr;
	snd_context_t		snd_ctx;
	struct _io_write	*write;
	struct _io_write_reply	*reply;
	int		tbytes, nbytes;

	write = (struct _io_write *) msg;
	reply = (struct _io_write_reply *) msg;

	snd_ctx.ocb = ocb_list[__get_fd(pid, write->fd, fd_ctrl)];
	snd_attr = snd_ctx.ocb->iofunc_ocb.attr;

	if ((ptr = snd_attr->io.write) == NULL) {
		reply->status = ENXIO;
		reply->nbytes = 0;
		goto reply;
	}

	/* verify we can write, check for nonblocking mode */
	snd_ctx.pid = pid;
	snd_ctx.nonblock = (snd_ctx.ocb->iofunc_ocb.ioflag & _IO_FLAG_NONBLOCK);
	snd_ctx.rw_offset = sizeof(struct _io_write) - sizeof(char[1]);

	tbytes = write->nbytes;
	if ((nbytes = ptr(&snd_ctx, tbytes)) >= 0)
	{
		if(tbytes == MAX_WRITE_SIZE)		
			reply->status = EMORE;
		else
			reply->status = EOK;
		reply->nbytes = nbytes;
		goto reply;
	}

	reply->status = -nbytes;
	reply->nbytes = 0;

reply:
	snd_attr->attr.ino_mtime = snd_attr->attr.ino_ctime = *timeptr;
	Reply(pid, reply, sizeof(*reply));        

	return (0);
}

static int
snd_select(int minor, pid_t pid, caddr_t msg)
{

	struct _io_select		*select;
	struct _io_select_reply		*reply;
	snd_attr_t			*snd_attr;
	snd_ocb_t			*ocb;
        struct _mxfer_entry 		mx[2];
        struct _select_set 		*array, *p;
        int 				alloc_size, ret;
        int				notify = 0, count = 0;
	int				nfds;

	select = (struct _io_select *) msg;
	reply = (struct _io_select_reply *) msg;

	nfds = select->nfds;

        /* since select is a variable length message we have to make sure to get all of it */
        alloc_size = nfds * sizeof(struct _select_set); /* what needs to have been/be read */

        if(( array = snd_malloc(alloc_size)) == NULL ) {
                reply->status= ENOMEM;
		goto reply;
        }

        if (Readmsg(pid, offsetof(struct _io_select, set), (void*) array, alloc_size) == -1) {
                reply->status= errno;
		goto reply;
        }

	while(nfds--) {
		int sel_fd;

		p = &array[nfds];

		if( p->flag & _SEL_POLLED ) 
			continue;

		/* is this fd ours? */
		if(( sel_fd = __get_fd(pid, p->fd, fd_ctrl)) < 0 ) 
			/* nope */
			continue;

		p->flag |= _SEL_POLLED;

		/* get ocb and attr corresponding to fd */
		ocb = ocb_list[sel_fd];
                snd_attr = ocb->iofunc_ocb.attr;

		if(( ret = snd_attr->io.io_notify( ocb, &notify )) < 0 ) {
			reply->status = -ret;
			goto reply;
		}

		if (p->flag & _SEL_INPUT) {
		        if (notify & NOTIFY_INPUT) {
				count++;
		                p->flag |= _SEL_IS_INPUT;
			/* Arm */
        		} else if( select->mode == _SEL_ARM ) {
      	        		p->flag |= _SEL_ARMED;
				memcpy(&ocb->notify[0].set, p, sizeof(*p));
				ocb->notify[0].proxy = select->proxy;
			}
			/* Disarm */
			if( select->mode == _SEL_POLL ) {
				p->flag &= ~_SEL_ARMED;
				memset( &ocb->notify[0], 0, sizeof(iofunc_notify_t)); 
			}
		}
		if (p->flag & _SEL_OUTPUT) {
			if (notify & NOTIFY_OUTPUT) {
				count++;
				p->flag |= _SEL_IS_OUTPUT;
			/* Arm */
			} else if( select->mode == _SEL_ARM ) {
				p->flag |= _SEL_ARMED;
				memcpy(&ocb->notify[1].set, p, sizeof(*p));
				ocb->notify[1].proxy = select->proxy;
			}
			/* Disarm */
			if( select->mode == _SEL_POLL ) {
				p->flag &= ~_SEL_ARMED;
				memset( &ocb->notify[1], 0, sizeof(iofunc_notify_t)); 
			}
		}
		if (p->flag & _SEL_EXCEPT) {
			if (notify & NOTIFY_EXCEPT) {
				count++;
				p->flag |= _SEL_IS_EXCEPT;
			/* Arm */
			} else if( select->mode == _SEL_ARM ) {
				p->flag |= _SEL_ARMED;
				memcpy(&ocb->notify[2].set, p, sizeof(*p));
				ocb->notify[2].proxy = select->proxy;
			}
			/* Disarm */
			if( select->mode == _SEL_POLL ) {
				p->flag &= ~_SEL_ARMED;
				memset( &ocb->notify[2], 0, sizeof(iofunc_notify_t)); 
			}
		}
	}

        reply->nfds = count;
	reply->status = EOK;

 reply:

        _setmx(&mx[0], reply, sizeof(struct _io_select_reply));
        _setmx(&mx[1], array, alloc_size);
        if (Replymx(pid, 2, &mx) < 0)
                perror("Replymx");

        snd_free(array, alloc_size);
        return (EOK);
}


static int
snd_close(int minor, pid_t pid, caddr_t msg)
{
        snd_attr_t		*snd_attr;
	snd_close_t		*ptr;
	snd_ocb_t		*ocb;
        int			ret;
        int			idx;
	struct _io_close	*close;
	struct _io_close_reply	*reply;

	close = (struct _io_close *) msg;
	reply = (struct _io_close_reply *) msg;

	idx = __get_fd(pid, close->fd, fd_ctrl);

	if((ocb = ocb_list[idx]) == 0) {
		printf(" 	This OCB is already closed!!! idx = %i\n", idx);
		reply->status =  ENXIO;
		return Reply(pid, reply, sizeof(*reply));
	}

	snd_attr = ocb->iofunc_ocb.attr;
	snd_attr->attr.ino_nlink--;
	
        if ((ptr = snd_attr->io.close) == NULL) {
		if( ocb && ((!snd_attr) || (!snd_attr->attr.ino_nlink)) )
			snd_free (ocb, sizeof(snd_ocb_t));
		reply->status =  ENXIO;
                return Reply(pid, reply, sizeof(*reply));
	}
	
	ret = ptr((snd_ocb_t*) ocb);
	if( ocb && ((!snd_attr) || (!snd_attr->attr.ino_nlink)) )
        	snd_free(ocb, sizeof(snd_ocb_t));

        ocb_list[idx] = NULL;

	qnx_fd_attach(pid, close->fd, 0, 0, 0, 0, 0);

        reply->status = EOK;
	Reply(pid, reply, sizeof(*reply));

        return (0);
}


/* iomgr helper funcs */

static int
chk_perm(uid_t u, gid_t g, mode_t io_mode, iofunc_attr_t *obj)
{
        unsigned        okmode;
        unsigned        fuid, fgid;
        mode_t          fmode;
	mode_t          mode = 0;

	if (io_mode & _IO_FLAG_RD)
		mode |= FREAD;
	if (io_mode & _IO_FLAG_WR)
		mode |= FWRITE;

        fuid = d_owner(obj);
        if (mode == FNONE)
                return EOK;
        if (mode == FOWNER) {
                return (u == 0 || u == fuid) ?  EOK : EPERM;
        }
        fgid = d_group(obj);
        fmode = d_mode(obj);
        if (u == 0) {
                okmode = S_IRWXO;
        } else if (u == fuid) {
                okmode = (fmode >> 6) & 007;
        } else if (g == fgid) {
                okmode = (fmode >> 3) & 007;
        } else {
                okmode = fmode & 007;
        }
        mode &= FACC;
        return (mode&okmode)==mode ? EOK : EPERM;
}


static void
ids(pid_t pid, uid_t *u, gid_t *g)
{
        struct _psinfo3 psdata3;
        __get_pid_info(pid, &psdata3, fd_ctrl);
        *u = psdata3.euid;
        *g = psdata3.egid;
}


static void
iofunc_attr_init(iofunc_attr_t *attr, mode_t mode)
{
        static ino_t p = 1;

        attr->ino_ino = p++;

        /* We don't really handle minor numbers right now...maybe later */
        attr->ino_dev = attr->ino_rdev = 
                makedev(getnid(), attr->major, attr->minor);

        attr->ino_size = 0;
        attr->ino_nlink = 0;
        attr->ino_ftype = mode;
        attr->ino_mtime = attr->ino_atime = attr->ino_ctime = *timeptr;
	attr->ino_uid = geteuid(); /* or getuid?? */
	attr->ino_gid = getgid();
}


static short int
set_file_flags(short int ioflag)
{
        int rval = 0;

        switch (ioflag & 0xf) {

        case O_RDONLY:
                rval |= _IO_FLAG_RD;
                break;
        case O_WRONLY:
                rval |= _IO_FLAG_WR;
                break;
        case O_RDWR:
                rval |= _IO_FLAG_RD | _IO_FLAG_WR;
                break;
        default:
                break;
        }
	if (ioflag & 0x80)	/* magic?? */
		rval |= _IO_FLAG_NONBLOCK;

        return (rval);
}


static int 
ocb_attach(pid_t pid, short int fd, snd_ocb_t *ocb)
{
        int 			i;

        for (i = 0; i < MAX_OPEN_FILES; i++) {
                if (ocb_list[i] == NULL)
                        break;
        }
        assert(i < MAX_OPEN_FILES);

        if (qnx_fd_attach(pid, fd, 0, 0, 0, 0, i) < 0) {
                perror("qnx_fd_attach");
                return (-1);
        }

        ocb_list[i] = ocb;
        return (0);
}


static int 
register_device(snd_attr_t *snd_attr, char *dev_name)
{
        int 			i;

        iofunc_attr_init(&snd_attr->attr, S_IFCHR | 0666);

        if (qnx_prefix_attach(dev_name, NULL, snd_attr->id) < 0) {
                perror("qnx_prefix_attach");
                return (-1);
        }

        for (i = 0; i < MAX_DEVICES; i++) {
                if (snd_devices[i].pfx == NULL)
                        break;
        }
        assert(i < MAX_DEVICES);

	snd_devices[i].pfx = snd_malloc_strdup(dev_name);
        snd_devices[i].attr = snd_attr;

	return (0);
}

static void
signal_handler(int sig)
{
	int i;

	printf("Got a signal: %d\n", sig);

	for (i = 0; i < SND_CARDS; i++) {
                if (intr_thread_pids[i])
                        kill(intr_thread_pids[i], SIGTERM);
        }

        exit(0);
}


#endif






