/*
 * Copyright (C) 2002 Thomas Leibner (leibner@t-online.de) (first complete writeup)
 *	       2002 David Schleef (ds@schleef.org) (COMEDI master)
 *	       2002 Lorenzo Dozio (dozio@aero.polimi.it) (made it all work)
 *	       2002 Paolo Mantegazza (mantegazza@aero.polimi.it) (hints/support)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */


#ifndef _RTAI_COMEDI_H_
#define _RTAI_COMEDI_H_

#include <rtai_types.h>
#include <rtai_sem.h>

#define FUN_COMEDI_LXRT_INDX  9

#define _KCOMEDI_OPEN 			 0
#define _KCOMEDI_CLOSE 			 1
#define _KCOMEDI_LOCK 			 2
#define _KCOMEDI_UNLOCK 		 3
#define _KCOMEDI_CANCEL 		 4
#define _KCOMEDI_REGISTER_CALLBACK 	 5
#define _KCOMEDI_COMMAND 		 6
#define _KCOMEDI_COMMAND_TEST 		 7

/* DEPRECATED function */
#define _KCOMEDI_TRIGGER 		 8

#define _KCOMEDI_DATA_WRITE 		 9
#define _KCOMEDI_DATA_READ 		10
#define _KCOMEDI_DIO_CONFIG 		11
#define _KCOMEDI_DIO_READ 		12
#define _KCOMEDI_DIO_WRITE 		13
#define _KCOMEDI_DIO_BITFIELD 		14
#define _KCOMEDI_GET_N_SUBDEVICES 	15
#define _KCOMEDI_GET_VERSION_CODE 	16
#define _KCOMEDI_GET_DRIVER_NAME 	17
#define _KCOMEDI_GET_BOARD_NAME 	18
#define _KCOMEDI_GET_SUBDEVICE_TYPE 	19
#define _KCOMEDI_FIND_SUBDEVICE_TYPE	20
#define _KCOMEDI_GET_N_CHANNELS 	21
#define _KCOMEDI_GET_MAXDATA 		22
#define _KCOMEDI_GET_N_RANGES 		23
#define _KCOMEDI_DO_INSN 		24
#define _KCOMEDI_DO_INSN_LIST		25  // not yet in kcomedilib... (tl)
#define _KCOMEDI_POLL 			26

/* DEPRECATED function */
#define _KCOMEDI_GET_RANGETYPE 		27

/* ALPHA functions */
#define _KCOMEDI_GET_SUBDEVICE_FLAGS 	28
#define _KCOMEDI_GET_LEN_CHANLIST 	29
#define _KCOMEDI_GET_KRANGE 		30
#define _KCOMEDI_GET_BUF_HEAD_POS	31
#define _KCOMEDI_SET_USER_INT_COUNT	32
#define _KCOMEDI_MAP 			33
#define _KCOMEDI_UNMAP 			34

/* RTAI specific callbacks from kcomedi to user space */
#define _KCOMEDI_WAIT			35
#define _KCOMEDI_WAIT_IF     		36
#define _KCOMEDI_WAIT_UNTIL  		37
#define _KCOMEDI_WAIT_TIMED  		38

/* RTAI specific functions to allocate/free comedi_cmd */
#define _KCOMEDI_ALLOC_CMD  		39
#define _KCOMEDI_FREE_CMD  		40

/* buffer control functions (together with idx 31 above)*/
#define _KCOMEDI_GET_BUFFER_CONTENTS 41
#define _KCOMEDI_MARK_BUFFER_READ 42
#define _KCOMEDI_GET_BUFFER_SIZE 43
#define _KCOMEDI_GET_BUFFER_OFFSET 44
#define _KCOMEDI_MARK_BUFFER_WRITTEN 45 // not yet in kcomedilib api... (al)
#define _KCOMEDI_MARK_WAIT_MUNGE 46

#ifdef __KERNEL__ /* For kernel module build. */

#include <linux/comedilib.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int rt_comedi_register_callback(
	void *dev,
	unsigned int subdev,
	unsigned int mask,
	SEM *sem
);

unsigned int rt_comedi_wait(
	SEM *sem,
	int *semcnt
);


unsigned int rt_comedi_mark_wait_munge(
	void *dev,
	unsigned int subdev,
	int oldbytes,
	int *newbytes,
	SEM *sem,
	int *semcnt
);

unsigned int rt_comedi_wait_if(
	SEM *sem,
	int *semcnt
);

unsigned int rt_comedi_wait_until(
	SEM *sem,
	RTIME until,
	int *semcnt
);

unsigned int rt_comedi_wait_timed(
	SEM *sem,
	RTIME delay,
	int *semcnt
);

char *rt_comedi_get_driver_name(
	void *dev,
	char *name
);

char *rt_comedi_get_board_name(
	void *dev,
	char *name
);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#else  /* __KERNEL__ not defined */

#include <string.h>
#include <asm/rtai_lxrt.h>
#include <rtai_shm.h>
#include <linux/comedi.h>

#define COMEDI_LXRT_SIZARG sizeof(arg)

RTAI_PROTO(void *, comedi_open,(const char *filename))
{
	char lfilename[COMEDI_NAMELEN];
	struct { char *minor; } arg = { lfilename };
	strncpy(lfilename, filename, COMEDI_NAMELEN - 1);
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_OPEN, &arg).v[LOW];
}

RTAI_PROTO(int, comedi_close,(void *dev))
{
	struct { void *dev; } arg = { dev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_CLOSE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_lock,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_LOCK, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_unlock,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_UNLOCK, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_cancel,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_CANCEL, &arg).i[LOW];
}

RTAI_PROTO(int, rt_comedi_register_callback,(void *dev, unsigned int subdev, unsigned int mask, SEM *sem))
{
	struct
	{
		void *dev; unsigned int subdev; unsigned int mask; SEM *sem;
	} arg = { dev, subdev, mask, sem };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_REGISTER_CALLBACK, &arg).i[LOW];
}

#define comedi_register_callback(dev, subdev, mask, cb, arg)  rt_comedi_register_callback(dev, subdev, mask, arg)

RTAI_PROTO(unsigned int, rt_comedi_wait,(SEM *sem, int *semcnt))
{
	int lsemcnt;
	unsigned int retval;
	struct { SEM *sem; int *semcnt; int size; } arg = { sem, &lsemcnt, sizeof(int *) };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT, &arg).i[LOW];
	if (semcnt) {
		*semcnt = lsemcnt;
	}
	return retval;
}

/**
 * allows buffer synchronisation between comedi driver and lxrt program in a single 
 * call. Can replace calls to comedi_mark_buffer_read, comedi_get_buffer_contents and 
 * rt_comedi_wait in an asynchronous _input_ acquisition.
 * @param dev (must be) a pointer to a comedi_t structure
 * @param subdev the number of the comedi subdevice to perform acquistion on
 * @param *newbytes reference to the number of bytes read by userspace 
 *	  before the function call and to the number of bytes written by the comedi driver
 *	  after the function call
 * @param *sem pointer to the RTAI semaphore used to synchronize comedi driver with
 *        lxrt program
 * @param *semcnt contains the semaphore count after return. 
 *	  In case of TRIG_WAKE_EOS it is increased by one for each scan
 * @return callback mask indicating transfer status (see comedi.h: "callback stuff")
 */
RTAI_PROTO(unsigned int, rt_comedi_mark_wait_munge,(void *dev, unsigned int subdev, int *newbytes, SEM *sem, int *semcnt))
{
	int lnewbytes, lsemcnt;
	unsigned int retval;
	if (newbytes) {
		lnewbytes = *newbytes;
    		struct { 
		    void *dev; unsigned int subdev; int oldbytes; int *newbytes; SEM *sem; int *semcnt; int nbsmsize;
		} arg = { dev, subdev, lnewbytes, &lnewbytes, sem, &lsemcnt, sizeof(int *)};
		retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_MARK_WAIT_MUNGE, &arg).i[LOW];

		*newbytes = lnewbytes;
		if (semcnt) {
		    *semcnt = lsemcnt;
		}
	}
	else {
		retval = rt_comedi_wait(sem, semcnt);
	}	
	return retval;
}

RTAI_PROTO(unsigned int, rt_comedi_wait_if,(SEM *sem, int *semcnt))
{
	int lsemcnt;
	unsigned int retval;
	struct { SEM *sem; int *semcnt; int size; } arg = { sem, &lsemcnt, sizeof(int *) };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_IF, &arg).i[LOW];
	if (semcnt) {
		*semcnt = lsemcnt;
	}
	return retval;
}

RTAI_PROTO(unsigned int, rt_comedi_wait_until,(SEM *sem, RTIME until, int *semcnt))
{
	int lsemcnt;
	unsigned int retval;
	struct { SEM *sem; RTIME until; int *semcnt; int size; } arg = { sem, until, &lsemcnt, sizeof(int *) };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_UNTIL, &arg).i[LOW];
	if (semcnt) {
		*semcnt = lsemcnt;
	}
	return retval;
}

RTAI_PROTO(unsigned int, rt_comedi_wait_timed,(SEM *sem, RTIME delay, int *semcnt))
{
	int lsemcnt;
	unsigned int retval;
	struct
	{
		SEM *sem; RTIME delay; int *semcnt; int size;
	} arg = { sem, delay, &lsemcnt, sizeof(int *) };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_TIMED, &arg).i[LOW];
	if (semcnt) {
		*semcnt = lsemcnt;
	}
	return retval;
}

RTAI_PROTO(int, comedi_command,(void *dev, comedi_cmd *cmd))
{
	struct { void *dev; comedi_cmd *cmd; } arg = { dev, cmd };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_COMMAND, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_command_test,(void *dev, comedi_cmd *cmd))
{
	struct { void *dev; comedi_cmd *cmd; } arg = { dev, cmd };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_COMMAND_TEST, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_trigger,(void *dev, unsigned int subdev, comedi_trig *it))
{
	return -1;
}

RTAI_PROTO(int, comedi_data_write,(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, lsampl_t data))
{
	struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int range; unsigned int aref; lsampl_t data; } arg = { dev, subdev, chan, range, aref, data };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DATA_WRITE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_data_read,(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, lsampl_t *data))
{
	int retval;
	lsampl_t ldata;
	struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int range; unsigned int aref; lsampl_t *data; } arg = { dev, subdev, chan, range, aref, &ldata };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DATA_READ, &arg).i[LOW];
	memcpy(data, &ldata, sizeof(lsampl_t));
	return retval;
}

RTAI_PROTO(int, comedi_dio_config,(void *dev, unsigned int subdev, unsigned int chan, unsigned int io))
{
	struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int io; } arg = { dev, subdev, chan, io };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_CONFIG, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_dio_read,(void *dev, unsigned int subdev, unsigned int chan, unsigned int *val))
{
	int retval;
	unsigned int lval;
	struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int *val; } arg = { dev, subdev, chan, &lval };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_READ, &arg).i[LOW];
	*val = lval;
	return retval;
}

RTAI_PROTO(int, comedi_dio_write,(void *dev, unsigned int subdev, unsigned int chan, unsigned int val))
{
	struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int val; } arg = { dev, subdev, chan, val };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_WRITE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_dio_bitfield,(void *dev, unsigned int subdev, unsigned int mask, unsigned int *bits))
{
	int retval;
	unsigned int lbits;
	struct { void *dev; unsigned int subdev; unsigned int mask; unsigned int *bits; } arg = { dev, subdev, mask, &lbits };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_BITFIELD, &arg).i[LOW];
	*bits = lbits;
	return retval;
}

RTAI_PROTO(int, comedi_get_n_subdevices,(void *dev))
{
	struct { void *dev;} arg = { dev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_N_SUBDEVICES, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_get_version_code,(void *dev))
{
	struct { void *dev;} arg = { dev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_VERSION_CODE, &arg).i[LOW];
}

RTAI_PROTO(char *, rt_comedi_get_driver_name,(void *dev, char *name))
{
	void *p;
	char lname[COMEDI_NAMELEN];
	struct { void *dev; char *name; } arg = { dev, lname };
	if ((p = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_DRIVER_NAME, &arg).v[LOW])) {
		strncpy(name, lname, COMEDI_NAMELEN);
		return name;
	}
	return 0;
}

RTAI_PROTO(char *, rt_comedi_get_board_name,(void *dev, char *name))
{
	void *p;
	char lname[COMEDI_NAMELEN];
	struct { void *dev; char *name; } arg = { dev, lname };
	if ((p = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BOARD_NAME, &arg).v[LOW])) {
		strncpy(name, lname, COMEDI_NAMELEN);
		return name;
	}
	return 0;
}

RTAI_PROTO(int, comedi_get_subdevice_type,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_SUBDEVICE_TYPE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_find_subdevice_by_type,(void *dev, int type, unsigned int subd))
{
	struct { void *dev; int type; unsigned int subd; } arg = { dev, type, subd };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_FIND_SUBDEVICE_TYPE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_get_n_channels,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_N_CHANNELS, &arg).i[LOW];
}

RTAI_PROTO(lsampl_t, comedi_get_maxdata,(void *dev, unsigned int subdev, unsigned int chan))
{
	struct { void *dev; unsigned int subdev; unsigned int chan;} arg = { dev, subdev, chan };
	return (lsampl_t)rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_MAXDATA, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_get_n_ranges,(void *dev, unsigned int subdev, unsigned int chan))
{
	struct { void *dev; unsigned int subdev; unsigned int chan;} arg = { dev, subdev, chan };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_N_RANGES, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_do_insn,(void *dev, comedi_insn *insn))
{
	int retval;
	comedi_insn linsn = *insn;
	struct { void *dev; comedi_insn *insn; } arg = { dev, &linsn };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DO_INSN, &arg).i[LOW];
	memcpy(insn, &linsn, sizeof(comedi_insn));
	return retval;
}

RTAI_PROTO(int, comedi_poll,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_POLL, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_get_krange,(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, comedi_krange *krange))
{
	int retval;
	comedi_krange lkrange;
	struct
	{
		void *dev; unsigned int subdev; unsigned int chan; unsigned int range; comedi_krange *krange;
	} arg = { dev, subdev, chan, range, &lkrange };

	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_KRANGE, &arg).i[LOW];
	memcpy(krange, &lkrange, sizeof(comedi_krange));
	return retval;
}

RTAI_PROTO(unsigned int, comedi_get_buf_head_pos,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BUF_HEAD_POS, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_map,(void *dev, unsigned int subdev, void *ptr))
{
	int retval;
	unsigned int liptr;
	struct { void *dev; unsigned int subdevice; void *ptr; } arg = { dev, subdev, &liptr };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_MAP, &arg).i[LOW];
	*((void **) ptr) = (void *)liptr;
	return retval;
}

RTAI_PROTO(int, comedi_unmap,(void *dev, unsigned int subdev))
{
	int retval;
	struct { void *dev; unsigned int subdevice; } arg = { dev, subdev };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_UNMAP, &arg).i[LOW];
	return retval;
}

RTAI_PROTO(int, comedi_get_len_chanlist,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_SUBDEVICE_FLAGS, &arg).i[LOW];
}

/**
 * allocates a RTAI SHM area for a comedi_cmd structure, a channel list, and
 * provides reference to Comedi's asynchronous DAQ transfer buffer.
 *
 * This function makes memory available for structures relevant for asynchronous
 * data acquisition. A shared memory area is allocated for the comedi_cmd
 * structure and the channel list array. Further the transfer buffer which is
 * maintained by comedi's DAQ driver is registered as a RTAI SHM segment to be
 * referenced by <em>data</em>.
 *
 * @param dev (must be) a pointer to a comedi_t structure
 * @param subdev the number of the comedi subdevice to perform acquistion on
 * @param chanlist reference to a channel list array's pointer
 * @param chanlist_len the length of the channel list (maximum is driver specific)
 * @param data reference to a pointer -- will be set to point to the comedi transfer buffer
 * @return pointer to a shm area for a comedi_cmd structure.
 */
RTAI_PROTO(
	comedi_cmd *, rt_comedi_alloc_cmd,
	(
		void *dev, unsigned int subdev, unsigned int **chanlist, unsigned int chanlist_len, void **data
	)
)
{
	unsigned long ofst[2], name;
	comedi_cmd *cmd;
	comedi_cmd *p;

	if ((int)chanlist_len>comedi_get_len_chanlist(dev,subdev))
	    return NULL;
	if ((chanlist==NULL) || (data==NULL))
	    return NULL;

	struct
	{
		void *dev; unsigned int subdev; unsigned int chanlist_len; unsigned long *ofst;
	} arg = { dev, subdev, chanlist_len, ofst };

	name = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_ALLOC_CMD, &arg).i[LOW];

	cmd = p = (comedi_cmd *)rtai_malloc(name, 1);
	*chanlist = cmd->chanlist = (unsigned int *)((char *)p + ofst[0]);
	*data = rtai_malloc(name+1,1);
	cmd->data = (sampl_t*)data;
	return cmd;
}

RTAI_PROTO(void, rt_comedi_free_cmd,(void *cmd))
{
	unsigned long name;
	struct { void *cmd; } arg = { cmd };
	name = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_FREE_CMD, &arg).i[LOW];
	rtai_free(name+1,cmd->data);
	rtai_free(name, cmd);
}

RTAI_PROTO(int, comedi_get_buffer_contents,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BUFFER_CONTENTS, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_mark_buffer_read,(void *dev, unsigned int subdev, unsigned int num_bytes))
{
	struct { void *dev; unsigned int subdev; unsigned int num_bytes;} arg = { dev, subdev, num_bytes };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_MARK_BUFFER_READ, &arg).i[LOW];
}

/* This function is not declared as a kcomdilib symbol
RTAI_PROTO(int, comedi_mark_buffer_written,(void *dev, unsigned int subdev, unsigned int num_bytes))
{
	struct { void *dev; unsigned int subdev; unsigned int num_bytes;} arg = { dev, subdev, num_bytes };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_MARK_BUFFER_READ, &arg).i[LOW];
}
*/

RTAI_PROTO(int, comedi_get_buffer_size,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BUFFER_SIZE, &arg).i[LOW];
}

RTAI_PROTO(int, comedi_get_buffer_offset,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BUFFER_OFFSET, &arg).i[LOW];
}

RTAI_PROTO(unsigned int, comedi_get_subdevice_flags,(void *dev, unsigned int subdev))
{
	struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
	return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_SUBDEVICE_FLAGS, &arg).i[LOW];
}

#endif /* #ifdef __KERNEL__ */

#endif /* #ifndef _RTAI_COMEDI_H_ */
