linux/drivers/comedi/comedi_fops.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * comedi/comedi_fops.c
 * comedi kernel module
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 1997-2007 David A. Schleef <[email protected]>
 * compat ioctls:
 * Author: Ian Abbott, MEV Ltd. <[email protected]>
 * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
 */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/comedi/comedidev.h>
#include <linux/cdev.h>

#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/compat.h>

#include "comedi_internal.h"

/*
 * comedi_subdevice "runflags"
 * COMEDI_SRF_RT:		DEPRECATED: command is running real-time
 * COMEDI_SRF_ERROR:		indicates an COMEDI_CB_ERROR event has occurred
 *				since the last command was started
 * COMEDI_SRF_RUNNING:		command is running
 * COMEDI_SRF_FREE_SPRIV:	free s->private on detach
 *
 * COMEDI_SRF_BUSY_MASK:	runflags that indicate the subdevice is "busy"
 */
#define COMEDI_SRF_RT
#define COMEDI_SRF_ERROR
#define COMEDI_SRF_RUNNING
#define COMEDI_SRF_FREE_SPRIV

#define COMEDI_SRF_BUSY_MASK

/**
 * struct comedi_file - Per-file private data for COMEDI device
 * @dev: COMEDI device.
 * @read_subdev: Current "read" subdevice.
 * @write_subdev: Current "write" subdevice.
 * @last_detach_count: Last known detach count.
 * @last_attached: Last known attached/detached state.
 */
struct comedi_file {};

#define COMEDI_NUM_MINORS
#define COMEDI_NUM_SUBDEVICE_MINORS

static unsigned short comedi_num_legacy_minors;
module_param(comedi_num_legacy_minors, ushort, 0444);
MODULE_PARM_DESC();

unsigned int comedi_default_buf_size_kb =;
module_param(comedi_default_buf_size_kb, uint, 0644);
MODULE_PARM_DESC();

unsigned int comedi_default_buf_maxsize_kb =;
module_param(comedi_default_buf_maxsize_kb, uint, 0644);
MODULE_PARM_DESC();

static DEFINE_MUTEX(comedi_board_minor_table_lock);
static struct comedi_device
*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];

static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
static struct comedi_subdevice
*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];

static struct cdev comedi_cdev;

static void comedi_device_init(struct comedi_device *dev)
{}

static void comedi_dev_kref_release(struct kref *kref)
{}

/**
 * comedi_dev_put() - Release a use of a COMEDI device
 * @dev: COMEDI device.
 *
 * Must be called when a user of a COMEDI device is finished with it.
 * When the last user of the COMEDI device calls this function, the
 * COMEDI device is destroyed.
 *
 * Return: 1 if the COMEDI device is destroyed by this call or @dev is
 * NULL, otherwise return 0.  Callers must not assume the COMEDI
 * device is still valid if this function returns 0.
 */
int comedi_dev_put(struct comedi_device *dev)
{}
EXPORT_SYMBOL_GPL();

static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
{}

static void comedi_device_cleanup(struct comedi_device *dev)
{}

static bool comedi_clear_board_dev(struct comedi_device *dev)
{}

static struct comedi_device *comedi_clear_board_minor(unsigned int minor)
{}

static struct comedi_subdevice *
comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned int minor)
{}

static struct comedi_device *comedi_dev_get_from_board_minor(unsigned int minor)
{}

static struct comedi_device *
comedi_dev_get_from_subdevice_minor(unsigned int minor)
{}

/**
 * comedi_dev_get_from_minor() - Get COMEDI device by minor device number
 * @minor: Minor device number.
 *
 * Finds the COMEDI device associated with the minor device number, if any,
 * and increments its reference count.  The COMEDI device is prevented from
 * being freed until a matching call is made to comedi_dev_put().
 *
 * Return: A pointer to the COMEDI device if it exists, with its usage
 * reference incremented.  Return NULL if no COMEDI device exists with the
 * specified minor device number.
 */
struct comedi_device *comedi_dev_get_from_minor(unsigned int minor)
{}
EXPORT_SYMBOL_GPL();

static struct comedi_subdevice *
comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
{}

static struct comedi_subdevice *
comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
{}

static void comedi_file_reset(struct file *file)
{}

static void comedi_file_check(struct file *file)
{}

static struct comedi_subdevice *comedi_file_read_subdevice(struct file *file)
{}

static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file)
{}

static int resize_async_buffer(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       unsigned int new_size)
{}

/* sysfs attribute files */

static ssize_t max_read_buffer_kb_show(struct device *csdev,
				       struct device_attribute *attr, char *buf)
{}

static ssize_t max_read_buffer_kb_store(struct device *csdev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(max_read_buffer_kb);

static ssize_t read_buffer_kb_show(struct device *csdev,
				   struct device_attribute *attr, char *buf)
{}

static ssize_t read_buffer_kb_store(struct device *csdev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(read_buffer_kb);

static ssize_t max_write_buffer_kb_show(struct device *csdev,
					struct device_attribute *attr,
					char *buf)
{}

static ssize_t max_write_buffer_kb_store(struct device *csdev,
					 struct device_attribute *attr,
					 const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(max_write_buffer_kb);

static ssize_t write_buffer_kb_show(struct device *csdev,
				    struct device_attribute *attr, char *buf)
{}

static ssize_t write_buffer_kb_store(struct device *csdev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(write_buffer_kb);

static struct attribute *comedi_dev_attrs[] =;
ATTRIBUTE_GROUPS();

static const struct class comedi_class =;

static void comedi_free_board_dev(struct comedi_device *dev)
{}

static void __comedi_clear_subdevice_runflags(struct comedi_subdevice *s,
					      unsigned int bits)
{}

static void __comedi_set_subdevice_runflags(struct comedi_subdevice *s,
					    unsigned int bits)
{}

static void comedi_update_subdevice_runflags(struct comedi_subdevice *s,
					     unsigned int mask,
					     unsigned int bits)
{}

static unsigned int __comedi_get_subdevice_runflags(struct comedi_subdevice *s)
{}

static unsigned int comedi_get_subdevice_runflags(struct comedi_subdevice *s)
{}

static bool comedi_is_runflags_running(unsigned int runflags)
{}

static bool comedi_is_runflags_in_error(unsigned int runflags)
{}

/**
 * comedi_is_subdevice_running() - Check if async command running on subdevice
 * @s: COMEDI subdevice.
 *
 * Return: %true if an asynchronous COMEDI command is active on the
 * subdevice, else %false.
 */
bool comedi_is_subdevice_running(struct comedi_subdevice *s)
{}
EXPORT_SYMBOL_GPL();

static bool __comedi_is_subdevice_running(struct comedi_subdevice *s)
{}

bool comedi_can_auto_free_spriv(struct comedi_subdevice *s)
{}

/**
 * comedi_set_spriv_auto_free() - Mark subdevice private data as freeable
 * @s: COMEDI subdevice.
 *
 * Mark the subdevice as having a pointer to private data that can be
 * automatically freed when the COMEDI device is detached from the low-level
 * driver.
 */
void comedi_set_spriv_auto_free(struct comedi_subdevice *s)
{}
EXPORT_SYMBOL_GPL();

/**
 * comedi_alloc_spriv - Allocate memory for the subdevice private data
 * @s: COMEDI subdevice.
 * @size: Size of the memory to allocate.
 *
 * Allocate memory for the subdevice private data and point @s->private
 * to it.  The memory will be freed automatically when the COMEDI device
 * is detached from the low-level driver.
 *
 * Return: A pointer to the allocated memory @s->private on success.
 * Return NULL on failure.
 */
void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
{}
EXPORT_SYMBOL_GPL();

/*
 * This function restores a subdevice to an idle state.
 */
static void do_become_nonbusy(struct comedi_device *dev,
			      struct comedi_subdevice *s)
{}

static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{}

void comedi_device_cancel_all(struct comedi_device *dev)
{}

static int is_device_busy(struct comedi_device *dev)
{}

/*
 * COMEDI_DEVCONFIG ioctl
 * attaches (and configures) or detaches a legacy device
 *
 * arg:
 *	pointer to comedi_devconfig structure (NULL if detaching)
 *
 * reads:
 *	comedi_devconfig structure (if attaching)
 *
 * writes:
 *	nothing
 */
static int do_devconfig_ioctl(struct comedi_device *dev,
			      struct comedi_devconfig __user *arg)
{}

/*
 * COMEDI_BUFCONFIG ioctl
 * buffer configuration
 *
 * arg:
 *	pointer to comedi_bufconfig structure
 *
 * reads:
 *	comedi_bufconfig structure
 *
 * writes:
 *	modified comedi_bufconfig structure
 */
static int do_bufconfig_ioctl(struct comedi_device *dev,
			      struct comedi_bufconfig __user *arg)
{}

/*
 * COMEDI_DEVINFO ioctl
 * device info
 *
 * arg:
 *	pointer to comedi_devinfo structure
 *
 * reads:
 *	nothing
 *
 * writes:
 *	comedi_devinfo structure
 */
static int do_devinfo_ioctl(struct comedi_device *dev,
			    struct comedi_devinfo __user *arg,
			    struct file *file)
{}

/*
 * COMEDI_SUBDINFO ioctl
 * subdevices info
 *
 * arg:
 *	pointer to array of comedi_subdinfo structures
 *
 * reads:
 *	nothing
 *
 * writes:
 *	array of comedi_subdinfo structures
 */
static int do_subdinfo_ioctl(struct comedi_device *dev,
			     struct comedi_subdinfo __user *arg, void *file)
{}

/*
 * COMEDI_CHANINFO ioctl
 * subdevice channel info
 *
 * arg:
 *	pointer to comedi_chaninfo structure
 *
 * reads:
 *	comedi_chaninfo structure
 *
 * writes:
 *	array of maxdata values to chaninfo->maxdata_list if requested
 *	array of range table lengths to chaninfo->range_table_list if requested
 */
static int do_chaninfo_ioctl(struct comedi_device *dev,
			     struct comedi_chaninfo *it)
{}

/*
 * COMEDI_BUFINFO ioctl
 * buffer information
 *
 * arg:
 *	pointer to comedi_bufinfo structure
 *
 * reads:
 *	comedi_bufinfo structure
 *
 * writes:
 *	modified comedi_bufinfo structure
 */
static int do_bufinfo_ioctl(struct comedi_device *dev,
			    struct comedi_bufinfo __user *arg, void *file)
{}

static int check_insn_config_length(struct comedi_insn *insn,
				    unsigned int *data)
{}

static int check_insn_device_config_length(struct comedi_insn *insn,
					   unsigned int *data)
{}

/**
 * get_valid_routes() - Calls low-level driver get_valid_routes function to
 *			either return a count of valid routes to user, or copy
 *			of list of all valid device routes to buffer in
 *			userspace.
 * @dev: comedi device pointer
 * @data: data from user insn call.  The length of the data must be >= 2.
 *	  data[0] must contain the INSN_DEVICE_CONFIG config_id.
 *	  data[1](input) contains the number of _pairs_ for which memory is
 *		  allotted from the user.  If the user specifies '0', then only
 *		  the number of pairs available is returned.
 *	  data[1](output) returns either the number of pairs available (if none
 *		  where requested) or the number of _pairs_ that are copied back
 *		  to the user.
 *	  data[2::2] returns each (source, destination) pair.
 *
 * Return: -EINVAL if low-level driver does not allocate and return routes as
 *	   expected.  Returns 0 otherwise.
 */
static int get_valid_routes(struct comedi_device *dev, unsigned int *data)
{}

static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
		      unsigned int *data, void *file)
{}

/*
 * COMEDI_INSNLIST ioctl
 * synchronous instruction list
 *
 * arg:
 *	pointer to comedi_insnlist structure
 *
 * reads:
 *	comedi_insnlist structure
 *	array of comedi_insn structures from insnlist->insns pointer
 *	data (for writes) from insns[].data pointers
 *
 * writes:
 *	data (for reads) to insns[].data pointers
 */
/* arbitrary limits */
#define MIN_SAMPLES
#define MAX_SAMPLES
static int do_insnlist_ioctl(struct comedi_device *dev,
			     struct comedi_insn *insns,
			     unsigned int n_insns,
			     void *file)
{}

/*
 * COMEDI_INSN ioctl
 * synchronous instruction
 *
 * arg:
 *	pointer to comedi_insn structure
 *
 * reads:
 *	comedi_insn structure
 *	data (for writes) from insn->data pointer
 *
 * writes:
 *	data (for reads) to insn->data pointer
 */
static int do_insn_ioctl(struct comedi_device *dev,
			 struct comedi_insn *insn, void *file)
{}

static int __comedi_get_user_cmd(struct comedi_device *dev,
				 struct comedi_cmd *cmd)
{}

static int __comedi_get_user_chanlist(struct comedi_device *dev,
				      struct comedi_subdevice *s,
				      unsigned int __user *user_chanlist,
				      struct comedi_cmd *cmd)
{}

/*
 * COMEDI_CMD ioctl
 * asynchronous acquisition command set-up
 *
 * arg:
 *	pointer to comedi_cmd structure
 *
 * reads:
 *	comedi_cmd structure
 *	channel/range list from cmd->chanlist pointer
 *
 * writes:
 *	possibly modified comedi_cmd structure (when -EAGAIN returned)
 */
static int do_cmd_ioctl(struct comedi_device *dev,
			struct comedi_cmd *cmd, bool *copy, void *file)
{}

/*
 * COMEDI_CMDTEST ioctl
 * asynchronous acquisition command testing
 *
 * arg:
 *	pointer to comedi_cmd structure
 *
 * reads:
 *	comedi_cmd structure
 *	channel/range list from cmd->chanlist pointer
 *
 * writes:
 *	possibly modified comedi_cmd structure
 */
static int do_cmdtest_ioctl(struct comedi_device *dev,
			    struct comedi_cmd *cmd, bool *copy, void *file)
{}

/*
 * COMEDI_LOCK ioctl
 * lock subdevice
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
			 void *file)
{}

/*
 * COMEDI_UNLOCK ioctl
 * unlock subdevice
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
			   void *file)
{}

/*
 * COMEDI_CANCEL ioctl
 * cancel asynchronous acquisition
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
			   void *file)
{}

/*
 * COMEDI_POLL ioctl
 * instructs driver to synchronize buffers
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
			 void *file)
{}

/*
 * COMEDI_SETRSUBD ioctl
 * sets the current "read" subdevice on a per-file basis
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg,
			     struct file *file)
{}

/*
 * COMEDI_SETWSUBD ioctl
 * sets the current "write" subdevice on a per-file basis
 *
 * arg:
 *	subdevice number
 *
 * reads:
 *	nothing
 *
 * writes:
 *	nothing
 */
static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg,
			     struct file *file)
{}

static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
				  unsigned long arg)
{}

static void comedi_vm_open(struct vm_area_struct *area)
{}

static void comedi_vm_close(struct vm_area_struct *area)
{}

static int comedi_vm_access(struct vm_area_struct *vma, unsigned long addr,
			    void *buf, int len, int write)
{}

static const struct vm_operations_struct comedi_vm_ops =;

static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
{}

static __poll_t comedi_poll(struct file *file, poll_table *wait)
{}

static ssize_t comedi_write(struct file *file, const char __user *buf,
			    size_t nbytes, loff_t *offset)
{}

static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
			   loff_t *offset)
{}

static int comedi_open(struct inode *inode, struct file *file)
{}

static int comedi_fasync(int fd, struct file *file, int on)
{}

static int comedi_close(struct inode *inode, struct file *file)
{}

#ifdef CONFIG_COMPAT

#define COMEDI32_CHANINFO
#define COMEDI32_RANGEINFO
/*
 * N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
 * It's too late to change it now, but it only affects the command number.
 */
#define COMEDI32_CMD
/*
 * N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
 * It's too late to change it now, but it only affects the command number.
 */
#define COMEDI32_CMDTEST
#define COMEDI32_INSNLIST
#define COMEDI32_INSN

struct comedi32_chaninfo_struct {};

struct comedi32_rangeinfo_struct {};

struct comedi32_cmd_struct {};

struct comedi32_insn_struct {};

struct comedi32_insnlist_struct {};

/* Handle 32-bit COMEDI_CHANINFO ioctl. */
static int compat_chaninfo(struct file *file, unsigned long arg)
{}

/* Handle 32-bit COMEDI_RANGEINFO ioctl. */
static int compat_rangeinfo(struct file *file, unsigned long arg)
{}

/* Copy 32-bit cmd structure to native cmd structure. */
static int get_compat_cmd(struct comedi_cmd *cmd,
			  struct comedi32_cmd_struct __user *cmd32)
{}

/* Copy native cmd structure to 32-bit cmd structure. */
static int put_compat_cmd(struct comedi32_cmd_struct __user *cmd32,
			  struct comedi_cmd *cmd)
{}

/* Handle 32-bit COMEDI_CMD ioctl. */
static int compat_cmd(struct file *file, unsigned long arg)
{}

/* Handle 32-bit COMEDI_CMDTEST ioctl. */
static int compat_cmdtest(struct file *file, unsigned long arg)
{}

/* Copy 32-bit insn structure to native insn structure. */
static int get_compat_insn(struct comedi_insn *insn,
			   struct comedi32_insn_struct __user *insn32)
{}

/* Handle 32-bit COMEDI_INSNLIST ioctl. */
static int compat_insnlist(struct file *file, unsigned long arg)
{}

/* Handle 32-bit COMEDI_INSN ioctl. */
static int compat_insn(struct file *file, unsigned long arg)
{}

/*
 * compat_ioctl file operation.
 *
 * Returns -ENOIOCTLCMD for unrecognised ioctl codes.
 */
static long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{}
#else
#define comedi_compat_ioctl
#endif

static const struct file_operations comedi_fops =;

/**
 * comedi_event() - Handle events for asynchronous COMEDI command
 * @dev: COMEDI device.
 * @s: COMEDI subdevice.
 * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held.
 *
 * If an asynchronous COMEDI command is active on the subdevice, process
 * any %COMEDI_CB_... event flags that have been set, usually by an
 * interrupt handler.  These may change the run state of the asynchronous
 * command, wake a task, and/or send a %SIGIO signal.
 */
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{}
EXPORT_SYMBOL_GPL();

/* Note: the ->mutex is pre-locked on successful return */
struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
{}

void comedi_release_hardware_device(struct device *hardware_device)
{}

int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
{}

void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{}

static void comedi_cleanup_board_minors(void)
{}

static int __init comedi_init(void)
{}
module_init();

static void __exit comedi_cleanup(void)
{}
module_exit(comedi_cleanup);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();