⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fifos.c

📁 rtai-3.1-test3的源代码(Real-Time Application Interface )
💻 C
📖 第 1 页 / 共 4 页
字号:
		return -ENODEV;	}	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_CREATE, minor, size);	if (!atomic_cmpxchg(&fifo[minor].opncnt, 0, 1)) {		if (size <= PAGE_SIZE*32) {			if (!(buf = kmalloc(size, GFP_KERNEL))) {				fifo[minor].opncnt = 0;				return -ENOMEM;			}			fifo[minor].malloc_type = 'k';		} else {			if (!(buf = vmalloc(size))) {				fifo[minor].opncnt = 0;				return -ENOMEM;			}			fifo[minor].malloc_type = 'v';		}		fifo[minor].handler = do_nothing;		mbx_init(&(fifo[minor].mbx), size, buf);		mbx_sem_init(&(fifo[minor].sem), 0);		fifo[minor].pol_asyn_pended = 0;		fifo[minor].asynq = 0;	} else {		if (size > fifo[minor].mbx.size) {			rtf_resize(minor, size);		}		atomic_inc((atomic_t *)&fifo[minor].opncnt);	}	return 0;}/** * @ingroup fifos_ipc * Close a real-time FIFO * * rtf_destroy closes, in kernel space, a real-time fifo previously * created or reopened with rtf_create() or rtf_open_sized(). An internal * mechanism counts how many times a fifo was opened. Opens and closes must be * in pair. rtf_destroy should be called as many times as rtf_create was. * After the last close the fifo is really destroyed. * * No need for any particular function for the same service in user space, * simply use the standard Unix close. * * @return a non-negative value on success. Actually it is the open counter, that * means how many times rtf_destroy should be called yet to destroy the fifo. * * @return a a negative value is returned as described below. * @retval ENODEV if @a fifo is greater than or equal to RTF_NO. * @retval EINVAL if @a fifo refers to a not opened fifo. * * @note The equivalent of rtf_destroy in user space is the standard UNIX * close. */int rtf_destroy(unsigned int minor){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_DESTROY, minor, 0);	if (atomic_dec_and_test((atomic_t *)&fifo[minor].opncnt)) {		if (fifo[minor].malloc_type == 'k') {			kfree(fifo[minor].mbx.bufadr); 		} else {			vfree(fifo[minor].mbx.bufadr); 		}		fifo[minor].handler = do_nothing;		mbx_delete(&(fifo[minor].mbx));		fifo[minor].pol_asyn_pended = 0;		fifo[minor].asynq = 0;		fifo[minor].name[0] = 0;	}	return fifo[minor].opncnt;}/** * @ingroup fifos_ipc * Install a FIFO handler function. * * rtf_create_handler installs a handler which is executed when data is written * to or read from a real-time fifo. * * @param minor is an RT-FIFO that must have previously been created with a call * to rtf_create(). * * @param handler is a pointer on a function wich will be called whenever a * Linux process accesses that fifo. * * rtf_create_handler is often used in conjunction with rtf_get() to process * data acquired asynchronously from a Linux process. The installed handler * calls rtf_get() when data is present. Because the handler is only executed * when there is activity on the fifo, polling is not necessary. * * @retval 0 on success. * @retval EINVAL if @a fifo is greater than or equal to RTF_NO, or handler is * @c NULL. * * @note rtf_create_handler does not check if FIFO referred by @a fifo is open * or not. The next call of rtf_create will uninstall the handler just * "installed". */int rtf_create_handler(unsigned int minor, int (*handler) (unsigned int fifo)){	if (minor >= MAX_FIFOS || !handler) {		return -EINVAL;	}	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_CREATE_HANDLER, minor, handler);	fifo[minor].handler = handler;	return 0;}/** * @ingroup fifos_ipc * Write data to FIFO * * rtf_put tries to write a block of data to a real-time fifo previously created * with rtf_create(). * * @param minor is the ID with which the RT-FIFO was created. * @param buf points the block of data to be written. * @param count is the size of the block in bytes. * * This mechanism is available only in kernel space, i.e. either in real-time * tasks or handlers; Linux processes use a write to the corresponding * /dev/fifo\<n\> device to enqueue data to a fifo. Similarly, Linux processes * use read or similar functions to read the data previously written via rtf_put * by a real-time task. * * @return the number of bytes written on succes. Note that this value may * be less than @a count if @a count bytes of free space is not available in the * fifo. * @retval ENODEV if @a fifo is greater than or equal to RTF_NO. * @retval EINVAL if @a fifo refers to a not opened fifo. * * @note The equivalent of rtf_put in user space is the standard UNIX write, * which can be either blocking or nonblocking according to how you opened the * related device. */int rtf_put(unsigned int minor, void *buf, int count){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_PUT, minor, count);	count -= mbx_send_wp(&(fifo[minor].mbx), buf, count, 0);	return count;}int rtf_ovrwr_put(unsigned int minor, void *buf, int count){	VALID_FIFO;	return mbx_ovrwr_send(&(fifo[minor].mbx), buf, count, 0);}int rtf_put_if(unsigned int minor, void *buf, int count){	VALID_FIFO;	count -= mbx_send_if(&(fifo[minor].mbx), buf, count, 0);	return count;}/** * @ingroup fifos_ipc * Read data from FIFO * * rtf_get tries to read a block of data from a real-time fifo previously * created with a call to rtf_create(). * * @param minor is the ID with which the RT-FIFO was created. * @param buf points a buffer provided by the caller. * @param count is the size of @a buf in bytes. * * This mechanism is available only to real-time tasks; Linux processes use a * read from the corresponding fifo device to dequeue data from a fifo. * Similarly, Linux processes use write or similar functions to write the data * to be read via rtf_put() by a real-time task. * * rtf_get is often used in conjunction with rtf_create_handler() to process * data received asynchronously from a Linux process. A handler is installed * via rtf_create_handler(); this handler calls rtf_get to receive any data * present in the RT-FIFO as it becomes available. In this way, polling is not * necessary; the handler is called only when data is present in the fifo. * * @return the size of the received data block on success. Note that this * value may be less than count if count bytes of data is not available in the * fifo. * @retval ENODEV if @a fifo is greater than or equal to RTF_NO. * @retval EINVAL if @a fifo refers to a not opened fifo. * * @note The equivalent of rtf_get in user space is the standard UNIX read, * which can be either blocking or nonblocking according to how you opened the * related device. */int rtf_get(unsigned int minor, void *buf, int count){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_GET, minor, count);	count -= mbx_receive_wp(&(fifo[minor].mbx), buf, count, 0);	return count;}int rtf_evdrp(unsigned int minor, void *msg, int msg_size){	VALID_FIFO;	return msg_size - mbx_evdrp(&(fifo[minor].mbx), (char **)(&msg), msg_size, 0);}int rtf_get_if(unsigned int minor, void *buf, int count){	VALID_FIFO;	return count - mbx_send_if(&(fifo[minor].mbx), buf, count, 0);}/** * @ingroup fifos_sem * Initialize a binary semaphore * * rtf_sem_init initializes a semaphore identified by the file descriptor or * fifo number @a fd_fifo. * * A fifo semaphore can be used for communication and synchronization between * kernel and user space. * * @param minor is a file descriptor returned by standard UNIX open in user * space while it is directly the chosen fifo number in kernel space. In fact * fifos semaphores must be associated to a fifo for identification purposes. * @param value is the initial value of the semaphore, it must be either 0 or * 1. * * rt_sem_init can be used both in kernel and user space. * * @retval 0 on success. * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo. */int rtf_sem_init(unsigned int minor, int value){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_INIT, minor, value);	mbx_sem_init(&(fifo[minor].sem), value);	return 0;}/** * @ingroup fifos_sem * Posting (signaling) a semaphore. * * rtf_sem_post signal an event to a semaphore. The semaphore value is set to * one and the first process, if any, in semaphore's waiting queue is allowed to * run. * * @param minor is a file descriptor returned by standard UNIX open in user * space while it is directly the chosen fifo number in kernel space. In fact * fifos semaphores must be associated to a fifo for identification purposes. * * Since it is not blocking rtf_sem_post can be used both in kernel and user * space. * * @retval 0 on success. * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo. */int rtf_sem_post(unsigned int minor){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_POST, minor, 0);	mbx_sem_signal(&(fifo[minor].sem), 0);	return 0;}/** * @ingroup fifos_sem * Take a semaphore, only if the calling task is not blocked. * * rtf_sem_trywait is a version of the semaphore wait operation is similar to * rtf_sem_wait() but it is never blocks the caller.   If the semaphore is not * free, rtf_sem_trywait returns immediately and the semaphore value remains * unchanged. * * @param minor is a file descriptor returned by standard UNIX open in user * space while it is directly the chosen fifo number in kernel space. In fact * fifos semaphores must be associated to a fifo for identification purposes. * * Since it is not blocking rtf_sem_trywait can be used both in kernel and user * space. * * @retval 0 on success. * @retval EINVAL if @a fd_fifo  refers to an invalid file descriptor or fifo. */int rtf_sem_trywait(unsigned int minor){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_TRY_WAIT, minor, 0);	return mbx_sem_wait_if(&(fifo[minor].sem));}/** * @ingroup fifos_sem * Delete a semaphore * * rtf_sem_destroy deletes a semaphore previously created with rtf_sem_init(). * * @param minor is a file descriptor returned by standard UNIX open in user * space while it is directly the chosen fifo number in kernel space. In fact * fifos semaphores must be associated to a fifo for identification purposes. * * Any tasks blocked on this semaphore is returned in error and allowed to run * when semaphore is destroyed. * * rtf_sem_destroy can be used both in kernel and user space. * * @retval 0 on sucess. * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo. */int rtf_sem_destroy(unsigned int minor){	VALID_FIFO;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_DESTROY, minor, 0);	return mbx_sem_delete(&(fifo[minor].sem));}static int rtf_open(struct inode *inode, struct file *filp){#define DEFAULT_SIZE 1000	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_OPEN, MINOR(inode->i_rdev), DEFAULT_SIZE);	return rtf_create(MINOR(inode->i_rdev), DEFAULT_SIZE);}static int rtf_fasync(int fd, struct file *filp, int mode){		int minor;	minor = MINOR((filp->f_dentry->d_inode)->i_rdev);	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_FASYNC, minor, fd);	return fasync_helper(fd, filp, mode, &(fifo[minor].asynq));	if (!mode) {		fifo[minor].asynq = 0;	}}static int rtf_release(struct inode *inode, struct file *filp){	int minor;	minor = MINOR(inode->i_rdev);	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_RELEASE, minor, 0);	if (waitqueue_active(&(fifo[minor].pollq))) {		wake_up_interruptible(&(fifo[minor].pollq));	}	rtf_fasync(-1, filp, 0);	set_tsk_need_resched(current);	return rtf_destroy(minor);}static ssize_t rtf_read(struct file *filp, char *buf, size_t count, loff_t* ppos){	struct inode *inode = filp->f_dentry->d_inode;	unsigned int minor = MINOR(inode->i_rdev);	int handler_ret;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ, minor, count);	if (filp->f_flags & O_NONBLOCK) {		count -= mbx_receive_wp(&(fifo[minor].mbx), buf, count, 1);		if (!count) {			return -EAGAIN;		}	} else {		count -= mbx_receive_wjo(&(fifo[minor].mbx), buf, count, 1);	}	if (count) {		inode->i_atime = CURRENT_TIME;		if ((handler_ret = ((int (*)(int, ...))(fifo[minor].handler))(minor, 'r')) < 0) {			return handler_ret;		}		return count;	}	return 0;	return count;}static ssize_t rtf_write(struct file *filp, const char *buf, size_t count, loff_t* ppos){	struct inode *inode = filp->f_dentry->d_inode;	unsigned int minor = MINOR(inode->i_rdev);	int handler_ret;	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_WRITE, minor, count);	if (filp->f_flags & O_NONBLOCK) {		count -= mbx_send_wp(&(fifo[minor].mbx), (char *)buf, count, 1);		if (!count) {			return -EAGAIN;		}	} else {		count -= mbx_send(&(fifo[minor].mbx), (char *)buf, count, 1);	}	inode->i_ctime = inode->i_mtime = CURRENT_TIME;	if ((handler_ret = ((int (*)(int, ...))(fifo[minor].handler))(minor, 'w')) < 0) {		return handler_ret;	}	return count;}#define DELAY(x) (((x)*HZ + 500)/1000)static int rtf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){		unsigned int minor;	FIFO *fifop;	fifop = fifo + (minor = MINOR(inode->i_rdev));	TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_IOCTL, minor, cmd);	switch(cmd) {		case RESET: {			return rtf_reset(minor);		}		case RESIZE: {			return rtf_resize(minor, arg);		}		case SUSPEND_TIMED: {			TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SUSPEND_TIMED, DELAY(arg), 0);			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(DELAY(arg));			if (signal_pending(current)) {				return -ERESTARTSYS;			}			return 0;		}		case OPEN_SIZED: {			return rtf_create(minor, arg);		}		case READ_ALL_AT_ONCE: {			struct { char *buf; int count; } args;			int handler_ret;			TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ_ALLATONCE, 0, 0);			copy_from_user(&args, (void *)arg, sizeof(args));			args.count -= mbx_receive(&(fifop->mbx), args.buf, args.count, 1);			if (args.count) {				inode->i_atime = CURRENT_TIME;				if ((handler_ret = ((int (*)(int, ...))(fifo[minor].handler))(minor, 'r')) < 0) {					return handler_ret;				}				return args.count;			}			return 0;		}		case EAVESDROP: {			struct { char *buf; int count; } args;			copy_from_user(&args, (void *)arg, sizeof(args));			return args.count - mbx_evdrp(&(fifop->mbx), (char **)&args.buf, args.count, 1);		}		case READ_TIMED: {			struct { char *buf; int count, delay; } args;			int handler_ret;			copy_from_user(&args, (void *)arg, sizeof(args));			TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ_TIMED, args.count, DELAY(args.delay));			if (!args.delay) {				args.count -= mbx_receive_wp(&(fifop->mbx), args.buf, args.count, 1);				if (!args.count) {					return -EAGAIN;				}			} else {				args.count -= mbx_receive_timed(&(fifop->mbx), args.buf, args.count, DELAY(args.delay), 1);			}			if (args.count) {				inode->i_atime = CURRENT_TIME;//				if ((handler_ret = (fifop->handler)(minor)) < 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -