linux/drivers/comedi/drivers/usbdux.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * usbdux.c
 * Copyright (C) 2003-2014 Bernd Porr, [email protected]
 */

/*
 * Driver: usbdux
 * Description: University of Stirling USB DAQ & INCITE Technology Limited
 * Devices: [ITL] USB-DUX (usbdux)
 * Author: Bernd Porr <[email protected]>
 * Updated: 10 Oct 2014
 * Status: Stable
 *
 * Connection scheme for the counter at the digital port:
 * 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1.
 * The sampling rate of the counter is approximately 500Hz.
 *
 * Note that under USB2.0 the length of the channel list determines
 * the max sampling rate. If you sample only one channel you get 8kHz
 * sampling rate. If you sample two channels you get 4kHz and so on.
 */

/*
 * I must give credit here to Chris Baugher who
 * wrote the driver for AT-MIO-16d. I used some parts of this
 * driver. I also must give credits to David Brownell
 * who supported me with the USB development.
 *
 * Bernd Porr
 *
 *
 * Revision history:
 * 0.94: D/A output should work now with any channel list combinations
 * 0.95: .owner commented out for kernel vers below 2.4.19
 *       sanity checks in ai/ao_cmd
 * 0.96: trying to get it working with 2.6, moved all memory alloc to comedi's
 *       attach final USB IDs
 *       moved memory allocation completely to the corresponding comedi
 *       functions firmware upload is by fxload and no longer by comedi (due to
 *       enumeration)
 * 0.97: USB IDs received, adjusted table
 * 0.98: SMP, locking, memory alloc: moved all usb memory alloc
 *       to the usb subsystem and moved all comedi related memory
 *       alloc to comedi.
 *       | kernel | registration | usbdux-usb | usbdux-comedi | comedi |
 * 0.99: USB 2.0: changed protocol to isochronous transfer
 *                IRQ transfer is too buggy and too risky in 2.0
 *                for the high speed ISO transfer is now a working version
 *                available
 * 0.99b: Increased the iso transfer buffer for high sp.to 10 buffers. Some VIA
 *        chipsets miss out IRQs. Deeper buffering is needed.
 * 1.00: full USB 2.0 support for the A/D converter. Now: max 8kHz sampling
 *       rate.
 *       Firmware vers 1.00 is needed for this.
 *       Two 16 bit up/down/reset counter with a sampling rate of 1kHz
 *       And loads of cleaning up, in particular streamlining the
 *       bulk transfers.
 * 1.1:  moved EP4 transfers to EP1 to make space for a PWM output on EP4
 * 1.2:  added PWM support via EP4
 * 2.0:  PWM seems to be stable and is not interfering with the other functions
 * 2.1:  changed PWM API
 * 2.2:  added firmware kernel request to fix an udev problem
 * 2.3:  corrected a bug in bulk timeouts which were far too short
 * 2.4:  fixed a bug which causes the driver to hang when it ran out of data.
 *       Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it.
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include <linux/comedi/comedi_usb.h>

/* constants for firmware upload and download */
#define USBDUX_FIRMWARE
#define USBDUX_FIRMWARE_MAX_LEN
#define USBDUX_FIRMWARE_CMD
#define VENDOR_DIR_IN
#define VENDOR_DIR_OUT
#define USBDUX_CPU_CS

/* usbdux bulk transfer commands */
#define USBDUX_CMD_MULT_AI
#define USBDUX_CMD_AO
#define USBDUX_CMD_DIO_CFG
#define USBDUX_CMD_DIO_BITS
#define USBDUX_CMD_SINGLE_AI
#define USBDUX_CMD_TIMER_RD
#define USBDUX_CMD_TIMER_WR
#define USBDUX_CMD_PWM_ON
#define USBDUX_CMD_PWM_OFF

/* timeout for the USB-transfer in ms */
#define BULK_TIMEOUT

/* 300Hz max frequ under PWM */
#define MIN_PWM_PERIOD

/* Default PWM frequency */
#define PWM_DEFAULT_PERIOD

/* Size of one A/D value */
#define SIZEADIN

/*
 * Size of the input-buffer IN BYTES
 * Always multiple of 8 for 8 microframes which is needed in the highspeed mode
 */
#define SIZEINBUF

/* 16 bytes. */
#define SIZEINSNBUF

/* size of one value for the D/A converter: channel and value */
#define SIZEDAOUT

/*
 * Size of the output-buffer in bytes
 * Actually only the first 4 triplets are used but for the
 * high speed mode we need to pad it to 8 (microframes).
 */
#define SIZEOUTBUF

/*
 * Size of the buffer for the dux commands: just now max size is determined
 * by the analogue out + command byte + panic bytes...
 */
#define SIZEOFDUXBUFFER

/* Number of in-URBs which receive the data: min=2 */
#define NUMOFINBUFFERSFULL

/* Number of out-URBs which send the data: min=2 */
#define NUMOFOUTBUFFERSFULL

/* Number of in-URBs which receive the data: min=5 */
/* must have more buffers due to buggy USB ctr */
#define NUMOFINBUFFERSHIGH

/* Number of out-URBs which send the data: min=5 */
/* must have more buffers due to buggy USB ctr */
#define NUMOFOUTBUFFERSHIGH

/* number of retries to get the right dux command */
#define RETRIES

static const struct comedi_lrange range_usbdux_ai_range =;

static const struct comedi_lrange range_usbdux_ao_range =;

struct usbdux_private {};

static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs)
{}

static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink)
{}

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

static void usbduxsub_ai_handle_urb(struct comedi_device *dev,
				    struct comedi_subdevice *s,
				    struct urb *urb)
{}

static void usbduxsub_ai_isoc_irq(struct urb *urb)
{}

static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink)
{}

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

static void usbduxsub_ao_handle_urb(struct comedi_device *dev,
				    struct comedi_subdevice *s,
				    struct urb *urb)
{}

static void usbduxsub_ao_isoc_irq(struct urb *urb)
{}

static int usbdux_submit_urbs(struct comedi_device *dev,
			      struct urb **urbs, int num_urbs,
			      int input_urb)
{}

static int usbdux_ai_cmdtest(struct comedi_device *dev,
			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
{}

/*
 * creates the ADC command for the MAX1271
 * range is the range value from comedi
 */
static u8 create_adc_command(unsigned int chan, unsigned int range)
{}

static int send_dux_commands(struct comedi_device *dev, unsigned int cmd_type)
{}

static int receive_dux_commands(struct comedi_device *dev, unsigned int command)
{}

static int usbdux_ai_inttrig(struct comedi_device *dev,
			     struct comedi_subdevice *s,
			     unsigned int trig_num)
{}

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

/* Mode 0 is used to get a single conversion on demand */
static int usbdux_ai_insn_read(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_insn *insn,
			       unsigned int *data)
{}

static int usbdux_ao_insn_read(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_insn *insn,
			       unsigned int *data)
{}

static int usbdux_ao_insn_write(struct comedi_device *dev,
				struct comedi_subdevice *s,
				struct comedi_insn *insn,
				unsigned int *data)
{}

static int usbdux_ao_inttrig(struct comedi_device *dev,
			     struct comedi_subdevice *s,
			     unsigned int trig_num)
{}

static int usbdux_ao_cmdtest(struct comedi_device *dev,
			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
{}

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

static int usbdux_dio_insn_config(struct comedi_device *dev,
				  struct comedi_subdevice *s,
				  struct comedi_insn *insn,
				  unsigned int *data)
{}

static int usbdux_dio_insn_bits(struct comedi_device *dev,
				struct comedi_subdevice *s,
				struct comedi_insn *insn,
				unsigned int *data)
{}

static int usbdux_counter_read(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_insn *insn,
			       unsigned int *data)
{}

static int usbdux_counter_write(struct comedi_device *dev,
				struct comedi_subdevice *s,
				struct comedi_insn *insn,
				unsigned int *data)
{}

static int usbdux_counter_config(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn, unsigned int *data)
{}

static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev)
{}

static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink)
{}

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

static void usbduxsub_pwm_irq(struct urb *urb)
{}

static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev)
{}

static int usbdux_pwm_period(struct comedi_device *dev,
			     struct comedi_subdevice *s,
			     unsigned int period)
{}

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

static void usbdux_pwm_pattern(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       unsigned int chan,
			       unsigned int value,
			       unsigned int sign)
{}

static int usbdux_pwm_write(struct comedi_device *dev,
			    struct comedi_subdevice *s,
			    struct comedi_insn *insn,
			    unsigned int *data)
{}

static int usbdux_pwm_config(struct comedi_device *dev,
			     struct comedi_subdevice *s,
			     struct comedi_insn *insn,
			     unsigned int *data)
{}

static int usbdux_firmware_upload(struct comedi_device *dev,
				  const u8 *data, size_t size,
				  unsigned long context)
{}

static int usbdux_alloc_usb_buffers(struct comedi_device *dev)
{}

static void usbdux_free_usb_buffers(struct comedi_device *dev)
{}

static int usbdux_auto_attach(struct comedi_device *dev,
			      unsigned long context_unused)
{}

static void usbdux_detach(struct comedi_device *dev)
{}

static struct comedi_driver usbdux_driver =;

static int usbdux_usb_probe(struct usb_interface *intf,
			    const struct usb_device_id *id)
{}

static const struct usb_device_id usbdux_usb_table[] =;
MODULE_DEVICE_TABLE(usb, usbdux_usb_table);

static struct usb_driver usbdux_usb_driver =;
module_comedi_usb_driver();

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