Help porting 2.4 usb driver to 2.6

Greg KH <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
Hi all,

Here's a driver that was written for 2.4 and needs some help getting
working properly for 2.6.  I've taken a quick first cut, but it still
doesn't even build properly.

If anyone is looking for something to do, I know a lot of different
users of this driver would appreciate it (someone today just emailed me
about it...)

If anyone has questions about the device behind this driver, Mark has
lots of information and specs.

So, any help would be appreciated.

Oh, I don't think this driver would be acceptable for the main tree due
to the large number of ioctls, but feel free to prove me wrong :)

thanks,

greg k-h

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
usb-stimulus.patch (text/plain, 73.5 KB)
---
 drivers/usb/misc/Kconfig                |    2 
 drivers/usb/misc/Makefile               |    1 
 drivers/usb/misc/stimulus/Kconfig       |    6 
 drivers/usb/misc/stimulus/Makefile      |    2 
 drivers/usb/misc/stimulus/STG200x_def.h |  129 +
 drivers/usb/misc/stimulus/commands.h    |  571 ++++++++
 drivers/usb/misc/stimulus/stimulus.c    | 2070 ++++++++++++++++++++++++++++++++
 7 files changed, 2781 insertions(+)

--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -224,6 +224,8 @@ config USB_APPLEDISPLAY
 
 source "drivers/usb/misc/sisusbvga/Kconfig"
 
+#source "drivers/usb/misc/stimulus/Kconfig"
+
 config USB_LD
 	tristate "USB LD driver"
 	depends on USB
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_USB_TRANCEVIBRATOR)	+= tran
 obj-$(CONFIG_USB_USS720)	+= uss720.o
 
 obj-$(CONFIG_USB_SISUSBVGA)	+= sisusbvga/
+obj-$(CONFIG_USB_STIMULUS)	+= stimulus/
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
--- /dev/null
+++ b/drivers/usb/misc/stimulus/Kconfig
@@ -0,0 +1,6 @@
+
+config USB_STIMULUS
+	tristate "USB Stimulus Generator 2000 device support"
+	depends on USB
+
+
--- /dev/null
+++ b/drivers/usb/misc/stimulus/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_USB_STIMULUS) += stimulus.o
+
--- /dev/null
+++ b/drivers/usb/misc/stimulus/STG200x_def.h
@@ -0,0 +1,129 @@
+//---------------------------------------------------------------------------
+//
+// Project: MC_Stimulus200x
+// Copyright (c) 2003 Multi Channel Systems, all rights reserved
+//
+// $Workfile: STG200x_def.h $
+//
+// Description: interface for the CStgUsbPort class:
+//				Communication between PC application and Coldfire
+//			    firmware in the MCS STG 200x
+//
+//
+//---------------------------------------------------------------------------
+
+#ifndef _STG200x_DEF_H_
+#define _STG200x_DEF_H_
+
+
+/***********************************************************************
+ *
+ * defines needed by Windows
+ *
+ ***********************************************************************/
+
+#ifndef __GNUC__
+
+#ifdef INITGUID
+#include "initguid.h"
+#endif
+
+// guid of MCS_STG class
+//{42A81DA5-E416-403b-836C-7586A512066A}
+//DEFINE_GUID(GUID_MCS_STG, 0x42a81da5L, 0xe416, 0x403b, 0x83, 0x6c, 0x75, 0x86, 0xa5, 0x12, 0x06, 0x6a);
+
+// MOTUSB Device Object Interface ID
+// from the Motorola driver (function IoRegisterDeviceInterface())
+DEFINE_GUID(XGUID_CLASS_MOTUSB, 0x239d60c9, 0xccaf, 0x11d5, 0xac, 0x21, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20);
+
+#define WM_STG200x_STATUS  (WM_USER+20)
+
+#endif
+
+
+/***********************************************************************
+ *
+ * defines for the STG200x
+ *
+ ***********************************************************************/
+
+
+#define STG200x_NUM_CHANNELS   8
+#define STG200x_NUM_SYNC_OUT   4
+#define STG200x_NUM_TRIGGER    4
+
+#define STG200x_MAX_SEGMENTS    100
+#define STG200x_MAX_SAMPLERATE  50000
+
+#define STG200x_BYTES_PER_SAMPLE (2*STG200x_NUM_CHANNELS)
+
+#define STG200x_IDENT_LENGTH    100
+#define STG200x_PROGINFO_LENGTH 512
+#define STG200x_VERSION_LENGTH  32
+
+#define STG200x_UL_BLOCKSIZE 256
+#define STG200x_DATA_BLOCKSIZE 2000
+
+
+#define STG200x_TRIGGER_IDLE     0
+#define STG200x_TRIGGER_RUNNING  1
+#define STG200x_TRIGGER_FINISHED 2
+
+// define how a trigger is handles while the STG is running
+
+#define STG200x_RETRIGGER_STOP    0
+#define STG200x_RETRIGGER_RESTART 1
+#define STG200x_RETRIGGER_IGNORE  2
+
+// error handling analog the motusb library, see motstatus.h
+
+#define STG200x_STATUS_MASK 0xA0100000L
+#define IS_STG200x_STATUS(Status) ( (Status) & STG200x_STATUS_MASK )
+
+#define STG200x_STATUS_OK			    0
+
+#define STG200x_STATUS_NOT_CONNECTED    (0xA0100001L)
+#define STG200x_STATUS_DEVICE_NOT_FOUND (0xA0100002L)
+#define STG200x_STATUS_DEVICE_LOCKED    (0xA0100003L)
+#define STG200x_STATUS_ERR_CONNECT      (0xA0100004L)
+#define STG200x_STATUS_ERR_OPEN         (0xA0100005L)
+
+#define STG200x_STATUS_STG_RUNNING      (0xA0100006L)
+#define STG200x_STG_NOTPROGRAMMED		(0xA0100007L)
+
+#define STG200x_STATUS_IPIPE_NOT_OPEN	(0xA0100008L)
+
+
+
+/***********************************************************************
+ *
+ * The basic data types
+ *
+ ***********************************************************************/
+
+typedef volatile unsigned char		vuint8;  /*  8 bits */
+typedef volatile unsigned short int	vuint16; /* 16 bits */
+typedef volatile unsigned long int	vuint32; /* 32 bits */
+
+typedef unsigned char		uint8;  /*  8 bits */
+typedef unsigned short int	uint16; /* 16 bits */
+typedef unsigned long int	uint32; /* 32 bits */
+#ifdef __GNUC__
+typedef unsigned long long  uint64; /* 64 bits */
+#else
+typedef unsigned __int64    uint64; /* 64 bits */
+#endif
+
+typedef signed char			int8;   /*  8 bits */
+typedef signed short int	int16;  /* 16 bits */
+typedef signed long int		int32;  /* 32 bits */
+#ifdef __GNUC__
+typedef signed long long    int64;  /* 64 bits */
+#else
+typedef __int64             int64;  /* 64 bits */
+#endif
+
+/***********************************************************************/
+
+#endif
+
--- /dev/null
+++ b/drivers/usb/misc/stimulus/commands.h
@@ -0,0 +1,571 @@
+#ifndef _COMMANDS_H_
+#define _COMMANDS_H_
+
+
+#ifndef DOXYGEN_DOC_FOR_CUSTOMER
+/*! \file
+ * \brief Define the structures need for communication with the STG200x
+ */
+
+#if 0
+#define PACK __attribute__((packed))
+#else
+#define PACK
+#endif
+
+#pragma pack(1)
+
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+/* Vendor requests */
+
+#define ISO_STOP   1
+#define ISO_START  2
+
+#define SETUP_TRIGGER      0x11
+
+#define CHANNEL_RESET      0x12
+#define CHANNEL_DATA       0x13
+#define SYNC_RESET         0x14
+#define SYNC_DATA          0x15
+#define SET_CAPACITY       0x16
+#define GET_MEM            0x17  // return the memory avaiable in the current segment
+
+#define STG_START          0x18
+#define STG_STOP           0x19
+#define STG_RESET_STATUS   0x20
+
+#define SET_SAMPLERATE     0x23
+
+#define DISABLE_TRIGGER    0x25
+#define ENABLE_TRIGGER     0x26
+#define DISABLE_AUTORESET  0x27
+#define ENABLE_AUTORESET   0x28
+
+#define GET_UVAL           0x30
+#define GET_IVAL           0x31
+
+
+#define GET_IDENT          0x40
+#define GET_PROGRAM_INFO   0x41
+#define SET_PROGRAM_INFO   0x42
+#define GET_VERSION        0x43
+#define GET_SWEEP_COUNT    0x44
+#define GET_TRIGGERMAP     0x45
+#define GET_SAMPLERATE     0x46
+#define GET_CAPACITY       0x47
+
+#define COMMAND_UPLOAD       0x50
+#define COMMAND_FLASH        0x51
+#define COMMAND_EEPROM       0x52
+#define COMMAND_COLDSTART    0x53
+#define COMMAND_BOARD_EEPROM 0x54
+
+
+#define COMMAND_RESET        0x60
+#define COMMAND_DOWNLOADMODE    0x61
+#define COMMAND_STREAMINGMODE   0x62
+
+#define COMMAND_CONT_MODE_OFF 0x63
+#define COMMAND_CONT_MODE_ON  0x64
+
+#define MULTIFILE_MODE_OFF    0x65
+#define MULTIFILE_MODE_ON     0x66
+
+#define GET_PRODUCT          0x71
+#define GET_MANUFACTURER     0x72
+#define GET_SERIALNUMBER     0x73
+#define GET_BCDDEVICE        0x74
+#define GET_BOARD_EEPROM     0x75
+
+#define GET_ASCII_VERSION    0x76
+#define GET_BUILT_DATE       0x77
+#define GET_BUILT_TIME       0x78
+
+#define SEGMENT_DEFINE       0x80
+#define SEGMENT_SELECT       0x81
+#define SEGMENT_START        0x83  // SEGMENT_SELECT && STG_START
+#define GET_TOTALMEM         0x84  // get total memory of the STG
+
+#define SETUP_RETRIGGER_MODE 0x86  // reaction on trigger while running
+
+#define DEBUG_CHANNELDATA    0x90
+
+#endif
+
+/********************************************************************/
+
+
+// -------------------------------------------------------------------------------------------
+
+typedef struct bulkcommand {
+    uint16 command        PACK;
+} bulkcommand;
+
+#ifdef __KERNEL__
+static int bulkcommand_elements = 1;
+static int bulkcommand_list[] = { 2 };
+#endif
+
+
+// -------------------------------------------------------------------------------------------
+#ifdef MCF5272
+/*! Stucture to define the base and end addresses of the
+ *  segments. Only used internally
+ */
+typedef struct segmentinfo {
+    char *base[STG200x_MAX_SEGMENTS];   /*!< pointer to the base address of the segments  */
+    char *end[STG200x_MAX_SEGMENTS];    /*!< pointer to the end address of the segments */
+} segmentinfo;
+#endif
+
+/*! Structure to define a list of segments.
+ * Used by STG200x_SegmentDefine().
+ */
+
+typedef struct segmentdef {
+	uint32  size[STG200x_MAX_SEGMENTS];  /*!< list of segment sizes in bytes */
+} segmentdef;
+
+#ifdef __KERNEL__
+static int segmentdef_elements = STG200x_MAX_SEGMENTS;
+static int segmentdef_list[STG200x_MAX_SEGMENTS] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+													 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
+#endif
+
+/*! Structure to define the segment to switch to.
+ *  Used by STG200x_SegmentSelect() */
+
+typedef struct segmentselect {
+	uint32  segment;    /*!< number of the segment to select */
+} segmentselect;
+
+#ifdef __KERNEL__
+static int segmentselect_elements = 1;
+static int segmentselect_list[1] = { 4 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure to define the memory layout of the current segment.
+ * Used by STG200x_SetCapacity()
+ */
+
+typedef struct capacity {
+    uint32  channelcapacity[STG200x_NUM_CHANNELS]   PACK;  /*!< Capacity in bytes for each channel */
+    uint32  synccapacity[STG200x_NUM_SYNC_OUT]      PACK;  /*!< Capacity in bytes for each syncout */
+} capacity;
+
+#ifdef __KERNEL__
+static int capacity_elements = STG200x_NUM_CHANNELS + STG200x_NUM_SYNC_OUT;
+static int capacity_list[STG200x_NUM_CHANNELS + STG200x_NUM_SYNC_OUT] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure for information on STG memory.
+ *  Used by STG200x_GetTotalMemory() and STG200x_GetMemory()
+ *
+ */
+
+typedef struct mem {
+    uint32  memory   PACK;  /*!< memory in bytes */
+} mem;
+
+#ifdef __KERNEL__
+static int mem_elements = 1;
+static int mem_list[] = { 4 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! structure used in STG200x_SetSemplerate() function
+ * it holds the new samplerate.
+ */
+
+typedef struct samplerate {
+	int32 rate;  /*!< samplerate in Hz */
+} samplerate;
+
+#ifdef __KERNEL__
+static int samplerate_elements = 1;
+static int samplerate_list[] = { 4 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+
+typedef struct programinfo {
+	char  info[STG200x_PROGINFO_LENGTH]   PACK;
+} programinfo;
+
+#ifdef __KERNEL__
+static int programinfo_elements = 1;
+static int programinfo_list[] = { -STG200x_PROGINFO_LENGTH };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure for version information of the STG.
+ *  Used by STG200x_GetVersionInfo()
+ *
+ */
+
+typedef struct version {
+	char  swmajor;                         /*!<  major number of the software in STG firmware */
+	char  swminor;                         /*!<  minor number of the software in STG firmware */
+	char  hwversion[STG200x_VERSION_LENGTH];   /*!<  hareware revision of the STG as found in onboard EEPROM */
+} version;
+
+#ifdef __KERNEL__
+static int version_elements = 3;
+static int version_list[] = { 1, 1, -STG200x_VERSION_LENGTH };
+#endif
+
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure holds a bitmap of triggers which are started or stopped.
+ *  Used by STG200x_Start() and STG2002_Stop().
+ *
+ */
+
+typedef struct startstop {
+    uint8  triggermap   PACK;  /*!< Bitmap of triggers to start and stop. Bit 0 corresponds to Trigger 1, ... */
+} startstop;
+
+#ifdef __KERNEL__
+static int startstop_elements = 1;
+static int startstop_list[] = { 1 };
+#endif
+
+
+/*! Structure holds a bitmap of triggers which are to be enabled or disabled
+ *  bit 0 to 3 : Trigger 0 to 3
+ *  bit 4      : Front Side button
+ */
+
+typedef struct endistrigger {
+    uint8  triggermask;  /*!< Bitmap of triggers to enable or disable */
+    uint32 triggercount; /*!< Number of allowed trigger */
+} endistrigger;
+
+#ifdef __KERNEL__
+static int endistrigger_elements = 2;
+static int endistrigger_list[] = { 1, 4 };
+#endif
+
+
+/*! Structure holds the segment number and
+ *  a bitmap of triggers which are started or stopped.
+ *  Used by STG200x_SegmentStart().
+ *
+ */
+
+
+typedef struct segmentstart {
+	uint32 segment      PACK;  /*!< Segment number to switch to before starting the STG */
+    uint8  triggermap   PACK;  /*!< Bitmap of triggers to start (see ::startstop) */
+} segmentstart;
+
+#ifdef __KERNEL__
+static int segmentstart_elements = 2;
+static int segmentstart_list[] = { 4, 1 };
+#endif
+
+
+// -------------------------------------------------------------------------------------------
+
+
+/*! Structure to define the connection between trigger,
+ * channels and syncout.
+ * Used by STG200x_SetupTrigger().
+ */
+
+typedef struct setuptrigger {
+    uint8   channelmap[STG200x_NUM_TRIGGER]     PACK;  /*!< Bitmap of channels which belong to each trigger */
+    uint8   syncmap[STG200x_NUM_TRIGGER]        PACK;  /*!< Bitmap of syncouts which belong to each trigger */
+	uint32  repeat[STG200x_NUM_TRIGGER]         PACK;  /*!< Repeat count for each trigger (0 = infinite) */
+	uint8   digoutmap[STG200x_NUM_TRIGGER]      PACK;  /*!< Bitmap of digouts which belong to each trigger */
+	uint8   autostart[STG200x_NUM_TRIGGER]      PACK;  /*!< Flag if trigger is started automatically in onlinemode */
+} setuptrigger;
+
+#ifdef __KERNEL__
+static int setuptrigger_elements = 2+STG200x_NUM_TRIGGER+2;
+static int setuptrigger_list[] = { -STG200x_NUM_TRIGGER, -STG200x_NUM_TRIGGER, 4,4,4,4,
+								   -STG200x_NUM_TRIGGER, -STG200x_NUM_TRIGGER };
+#endif
+
+/*! Structure which holds to current sweep and tigger count.
+ * Used by STG200x_GetSweepCount().
+ */
+
+typedef struct sweepcount {
+	uint32  sweeps[STG200x_NUM_TRIGGER];   /*!< Number of sweeps for the running trigger. Reset to zero at trigger */
+	uint32  triggers[STG200x_NUM_TRIGGER]; /*!< Number of trigger events. Reset to zero at download */
+} sweepcount;
+
+#ifdef __KERNEL__
+static int sweepcount_elements = 8;
+static int sweepcount_list[] = { 4,4,4,4, 4,4,4,4 };
+#endif
+
+
+// -------------------------------------------------------------------------------------------
+
+typedef struct channelreset {
+    uint16   channel     PACK;  // channel number
+} channelreset;
+
+#ifdef __KERNEL__
+static int channelreset_elements = 1;
+static int channelreset_list[] = { 2 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure which holds data for channels and syncout
+ * Only used internally.
+ */
+
+
+typedef struct channeldata {
+    uint16   command             PACK;  /*!< command (needed for bulk transfer) */
+    uint16   channel             PACK;  /*!< channel for which the data is */
+    uint16   len                 PACK;  /*!< number of data points */
+    int16    data[STG200x_DATA_BLOCKSIZE]  PACK;  /*!< list of data   */
+} channeldata;
+
+#ifdef __KERNEL__
+static int channeldata_elements = 4;
+static int channeldata_list[] = { 2, 2, 2, -2*STG200x_DATA_BLOCKSIZE };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+typedef struct syncoutreset {
+    uint16   syncout     PACK;  // syncout number
+} syncoutreset;
+
+#ifdef __KERNEL__
+static int syncoutreset_elements = 1;
+static int syncoutreset_list[] = { 2 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+typedef struct syncoutdata {
+    uint16   command             PACK;  // command (needed for bulk out)
+    uint16   syncout             PACK;  // syncout for which the data is
+    uint16   len                 PACK;  // number of data points
+    int16    data[STG200x_DATA_BLOCKSIZE]  PACK;  // list of data
+} syncoutdata;
+
+#ifdef __KERNEL__
+static int syncoutdata_elements = 4;
+static int syncoutdata_list[] = { 2, 2, 2, -2*STG200x_DATA_BLOCKSIZE };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure for information on STG resolution.
+ *  Used by STG200x_GetIVal() and STG200x_GetUVal()
+ *
+ */
+
+typedef struct getval {
+    uint32  range               PACK;  /*!< range of Voltage or Current outputs in mV and uA */
+    uint32  res                 PACK;  /*!< resolution of Voltage or Current outputs in mV and uA */
+} getval;
+
+#ifdef __KERNEL__
+static int getval_elements = 2;
+static int getval_list[] = { 4, 4 };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure for information on STG.
+ *  Used by STG200x_GetIdent()
+ *
+ */
+
+typedef struct getident {
+    char   buffer[STG200x_IDENT_LENGTH];
+} getident;
+
+
+#ifdef __KERNEL__
+static int getident_elements = 1;
+static int getident_list[] = { -STG200x_IDENT_LENGTH };
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+/*! Structure to hold data to be sent to STG.
+ *  Used by STG200x_UploadBlock()
+ *
+ */
+
+
+typedef struct upload_block {
+    uint16  block_number         PACK;  /*!< Block number */
+    char    data[STG200x_UL_BLOCKSIZE]   PACK;  /*!< list of data */
+} upload_block;
+
+#ifdef __KERNEL__
+static int upload_elements = 2;
+static int upload_list[] = { 2, -STG200x_UL_BLOCKSIZE};
+#endif
+
+// -------------------------------------------------------------------------------------------
+
+typedef struct flash_command {
+    uint8   *flash_addr      PACK;
+    uint32  flash_size       PACK;
+} flash_command;
+
+#ifdef __KERNEL__
+static int flash_elements = 2;
+static int flash_list[] = { 4, 4};
+#endif
+
+
+/*! Structure to hold information about the current trigger status of the STG.
+ *
+ */
+
+typedef struct trigger_status {
+	uint8  active_map;      /*!< Bitmap of currently active tiggers */
+	uint8  finished_map;    /*!< Bitmap of finished trigger */
+	uint8  reserved1;       /*!< reserved */
+	uint8  reserved2;       /*!< reserved */
+} trigger_status;
+
+/*! Structure used to reset the ::trigger_status of the STG.
+ *  Used by STG200x_ResetStatus().
+ */
+
+typedef struct reset_status {
+	uint8  reserved0;       /*!< reserved */
+	uint8  finished_map;    /*!< Bitmap of triggers for which status is to be reset to zero */
+	uint8  reserved1;       /*!< reserved */
+	uint8  reserved2;       /*!< reserved */
+} reset_status;
+
+
+#ifdef __KERNEL__
+static int reset_status_elements = 4;
+static int reset_status_list[] = { 1, 1, 1, 1};
+#endif
+
+
+typedef struct retrigger_mode {
+	uint32  same_trigger;
+	uint32  other_trigger;
+} retrigger_mode;
+
+
+#ifdef __KERNEL__
+static int retrigger_mode_elements = 2;
+static int retrigger_mode_list[] = { 4, 4};
+#endif
+
+
+
+/* data format in the user <-> kernel interface */
+
+typedef struct dev_channeldata {
+	uint16 channel[STG200x_NUM_CHANNELS];
+	uint8  digout;
+	uint8  syncout;
+} dev_channeldata;
+
+union device_data_record
+{
+	struct {
+		uint8   geraet  [32];
+		uint8   typ     [32];
+		uint8   firma   [32];
+		uint8   jahr    [8];
+
+		uint8   ser_no  [32];
+		uint8   hw_stand[32];
+		uint8   sw_stand[32];
+
+		uint8   gap1    [8];
+		uint8   gap2    [16];
+
+		uint8   baud;
+
+		uint8   echo;
+		uint8   debug;
+
+		uint8   gap3   [5];
+		uint8   gap4   [24];
+
+		int16   offset_1;
+		int16   offset_2;
+		int16   offset_3;
+		int16   offset_4;
+		int16   offset_5;
+		int16   offset_6;
+		int16   offset_7;
+	    int16   offset_8;
+
+		uint16  ures;
+		uint16  ires;
+		uint16  pres;
+
+		uint16  urange;
+		uint16  irange;
+		uint32  prange;
+
+		uint8   gap5[50];
+
+		uint8   dig_init;
+		uint8   trig_slope;
+		uint8   sweep_mode;
+		uint8   sync_mode;
+		uint8   prgdat_valid;
+
+		uint8   gap6[137];
+
+		uint8   password[32];
+
+		uint8   checksum;
+		uint8   komplement;
+	} device_data;
+	unsigned char field[512];
+};
+
+#ifdef __KERNEL__
+static int device_data_elements = 16;
+static int device_data_list[] = { -256, 2,2,2,2,2,2,2,2, 2,2,2, 2,2,4, -126 };
+#endif
+
+
+union  active_map_record {
+	struct {
+		uint8  channel;
+		uint8  syncout;
+		uint16 digout;
+	} active_map;
+	uint32 all;
+};
+
+
+#pragma pack()
+
+#endif
+#endif
--- /dev/null
+++ b/drivers/usb/misc/stimulus/stimulus.c
@@ -0,0 +1,2070 @@
+/*
+ * Driver for MCS Stimulus
+ *
+ * taken from usb skeleton driver
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman ([email protected])
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ *
+ *
+ * This driver is to be used as a skeleton driver to be able to create a
+ * USB driver quickly.  The design of it is based on the usb-serial and
+ * dc2xx drivers.
+ *
+ * Thanks to Oliver Neukum and David Brownell for their help in debugging
+ * this driver.
+ * */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "STG200x_def.h"
+#include "commands.h"
+
+#define RINGBUFFERSIZE (128*1024)
+#define WRITEBUFFERSIZE (32*1024)
+
+#define SYNCFRAMES 5
+#define DESCFRAMES 5
+
+#define COLDFIRE_NUMSBUF 2
+
+#define SYNC_PACKET_SIZE (3*STG200x_NUM_TRIGGER+16)
+
+#define MAX_READ_SIZE 8000
+
+#define dprintk(x)
+
+/*
+ * This macro checks if the coldfire is still operational. The 'coldfire'
+ * pointer must be valid, coldfire->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define COLDFIRE_IS_OPERATIONAL(coldfire) (\
+	(coldfire != NULL) && \
+	((coldfire)->dev != NULL) && \
+	((coldfire)->last_error == 0) && \
+	(!(coldfire)->remove_pending))
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
+
+/* Version Information */
+#define DRIVER_VERSION "v0.45"
+#define DRIVER_AUTHOR "MCS"
+#define DRIVER_DESC "MCS Stimulus"
+
+/* Module paramaters */
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* Define these values to match your device */
+#define USB_STIMULUS_VENDOR_ID	0xabcd
+#define USB_STIMULUS_PRODUCT_ID	0xc104
+//#define USB_STIMULUS_PRODUCT_ID       0x1235
+
+/* table of devices that work with this driver */
+static struct usb_device_id stimulus_table[] = {
+	{USB_DEVICE(USB_STIMULUS_VENDOR_ID, USB_STIMULUS_PRODUCT_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, stimulus_table);
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_STIMULUS_MINOR_BASE	200
+
+/* we can have up to this number of device plugged in at once */
+#define MAX_DEVICES		16
+
+/* This structure represents one Isoc request - URB and buffer */
+struct coldfire_sbuf {
+	char *data;
+	struct urb *urb;
+};
+
+/* Statistics that can be overlaid on screen */
+typedef struct coldfile_statistics {
+	unsigned long frame_num;	/* Sequential number of the frame */
+	unsigned long urb_count;	/* How many URBs we received so far */
+	unsigned long urb_length;	/* Length of last URB */
+	unsigned long data_count;	/* How many bytes we received */
+	unsigned long header_count;	/* How many frame headers we found */
+	unsigned long iso_skip_count;	/* How many empty ISO packets received */
+	unsigned long iso_err_count;	/* How many bad ISO packets received */
+} coldfire_statistics;
+
+#define	RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length
+#define	RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
+#define	RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length])
+
+typedef struct ring_queue {
+	unsigned char *queue;	/* Data from the Isoc data pump */
+	int length;		/* How many bytes allocated for the queue */
+	int wi;			/* That's where we write */
+	int ri;			/* Read from here until you hit write index */
+	wait_queue_head_t wqh;	/* Processes waiting */
+};
+
+/* Structure to hold all of our device specific stuff */
+struct coldfire_t {
+	struct usb_device *dev;			/* save off the usb device pointer */
+	struct usb_interface *interface;	/* the interface for this device */
+
+	unsigned char int_in_endp;
+	unsigned char iso_in_endp;
+	unsigned char iso_out_endp;
+	unsigned char bulk_out_endp;
+
+	spinlock_t lock;	/* DMA buffer access spinlock */
+
+	unsigned char minor;		/* the starting minor number for this device */
+	unsigned char num_ports;	/* the number of ports this device has */
+
+	char *data_ioctl;
+	char *data_coldfire;
+
+	unsigned char *write_buffer;
+
+	struct tq_struct tqueue;	/* task queue for line discipline waking up */
+	int open_count[4];		/* number of times this port has been opened */
+	int open_count_total;
+	struct semaphore sem;		/* locks this structure */
+
+	int int_in_data;
+
+	int int_in_rate;
+	int int_in_packet_len;
+	int iso_in_packet_len;
+	int iso_out_packet_len;
+	int bulk_out_packet_len;
+
+	//    unsigned int samplerate = STG200x_MAX_SAMPLERATE;
+
+	unsigned int freqn;	/* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+	unsigned int freqm[STG200x_NUM_TRIGGER];	/* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+	unsigned int freqmax;	/* maximum sampling rate, used for buffer management */
+	unsigned int phase[STG200x_NUM_TRIGGER];	/* phase accumulator */
+	//    unsigned int flags;      /* see FLG_ defines */
+
+	struct urb *int_urb;
+
+	struct coldfire_sbuf sync_urb[COLDFIRE_NUMSBUF];
+	struct coldfire_sbuf data_urb[COLDFIRE_NUMSBUF];
+
+	struct coldfire_statistics stats;
+
+	int last_error;
+	int remove_pending;
+
+	int sample_count;
+
+	struct ring_queue dp[STG200x_NUM_TRIGGER];
+	uint16 *trigger_buffer[STG200x_NUM_TRIGGER];
+
+	int streaming;
+	int int_active;
+
+	setuptrigger triggermap;
+
+	int debug;
+};
+
+/* local function prototypes */
+static unsigned int stimulus_poll(struct file *file, poll_table * wait);
+static ssize_t stimulus_write(struct file *file, const char *buffer,
+			      size_t count, loff_t * ppos);
+static int stimulus_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg);
+static int stimulus_open(struct inode *inode, struct file *file);
+static int stimulus_release(struct inode *inode, struct file *file);
+
+static int stimulus_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id);
+static void stimulus_disconnect(struct usb_interface *interface);
+
+int usb_start_iso(struct coldfire_t *coldfire);
+int usb_stop_iso(struct coldfire_t *coldfire);
+
+static int usbout_sync_prepare_desc(struct coldfire_t *coldfire,
+				    struct urb *urb);
+static int usbout_sync_retire_desc(struct coldfire_t *coldfire,
+				   struct urb *urb);
+static void usbout_sync_completed(struct urb *urb);
+
+static int usbout_prepare_desc(struct coldfire_t *coldfire, struct urb *urb);
+static int usbout_retire_desc(struct coldfire_t *coldfire, struct urb *urb);
+static void usbout_completed(struct urb *urb);
+
+static int copy_samples(struct coldfire_t *coldfire, unsigned char *dest,
+			int *num);
+
+/* array of pointers to our devices that are currently connected */
+static struct coldfire_t *minor_table[MAX_DEVICES];
+
+/* lock to protect the minor_table structure */
+static DECLARE_MUTEX(minor_table_mutex);
+
+/*
+ * File operations needed when we register this driver.
+ * This assumes that this driver NEEDS file operations,
+ * of course, which means that the driver is expected
+ * to have a node in the /dev directory. If the USB
+ * device were for a network interface then the driver
+ * would use "struct net_driver" instead, and a serial
+ * device would use "struct tty_driver".
+ */
+static struct file_operations stimulus_fops = {
+	.owner =	THIS_MODULE,
+	/* .read =		stimulus_read, */
+	.write = 	stimulus_write,
+	.poll = 	stimulus_poll,
+	.ioctl =	stimulus_ioctl,
+	.open = 	stimulus_open,
+	.release =	stimulus_release,
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver stimulus_driver = {
+	.name =		"stimulus",
+	.probe =	stimulus_probe,
+	.disconnect =	stimulus_disconnect,
+	.id_table = 	stimulus_table,
+};
+
+static struct usb_class_driver stimulus_class = {
+	.name =		"stimulus%d",
+	.fops =		&stimulus_fops,
+	.minor_base =	USB_STIMULUS_MINOR_BASE,
+};
+
+
+void *usbvideo_rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+	size = PAGE_ALIGN(size);
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);	/* Clear the ram out, no junk to the user */
+	adr = (unsigned long)mem;
+	while (size > 0) {
+		mem_map_reserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	return mem;
+}
+
+void usbvideo_rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	adr = (unsigned long)mem;
+	while ((long)size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+
+void RingQueue_Initialize(struct ring_queue *rq)
+{
+	assert(rq != NULL);
+	init_waitqueue_head(&rq->wqh);
+}
+
+void RingQueue_Allocate(struct ring_queue *rq, int rqLen)
+{
+	assert(rq != NULL);
+	assert(rqLen > 0);
+	rq->length = rqLen;
+	rq->queue = usbvideo_rvmalloc(rq->length);
+	assert(rq->queue != NULL);
+}
+
+int RingQueue_IsAllocated(const struct ring_queue *rq)
+{
+	if (rq == NULL)
+		return 0;
+	return (rq->queue != NULL) && (rq->length > 0);
+}
+
+void RingQueue_Free(struct ring_queue *rq)
+{
+	assert(rq != NULL);
+	if (RingQueue_IsAllocated(rq)) {
+		usbvideo_rvfree(rq->queue, rq->length);
+		rq->queue = NULL;
+		rq->length = 0;
+	}
+}
+
+int RingQueue_Dequeue(struct ring_queue *rq, unsigned char *dst, int len)
+{
+	int dequeued = 0;
+
+	assert(rq != NULL);
+	assert(dst != NULL);
+
+	while (len > 0) {
+		int m, q_rest;
+
+		q_rest = rq->length - rq->ri;
+		if (q_rest <= 0) {
+			rq->ri = 0;
+			q_rest = rq->length;
+		}
+		m = len;
+		assert(q_rest > 0);
+		if (m > q_rest) {
+			m = q_rest;
+		}
+
+		memmove(dst, rq->queue + rq->ri, m);
+		RING_QUEUE_ADVANCE_INDEX(rq, ri, m);
+
+		dst += m;
+		dequeued += m;
+		len -= m;
+	}
+
+	return dequeued;
+}
+
+int RingQueue_Enqueue(struct ring_queue *rq, const unsigned char *cdata, int n)
+{
+	int enqueued = 0;
+
+	assert(rq != NULL);
+	assert(cdata != NULL);
+	assert(rq->length > 0);
+	while (n > 0) {
+		int m, q_avail;
+
+		/* Calculate the largest chunk that fits the tail of the ring */
+		q_avail = rq->length - rq->wi;
+		if (q_avail <= 0) {
+			rq->wi = 0;
+			q_avail = rq->length;
+		}
+		m = n;
+		assert(q_avail > 0);
+		if (m > q_avail)
+			m = q_avail;
+
+		memmove(rq->queue + rq->wi, cdata, m);
+		RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
+		cdata += m;
+		enqueued += m;
+		n -= m;
+	}
+	return enqueued;
+}
+
+int RingQueue_GetLength(const struct ring_queue *rq)
+{
+	int ri, wi;
+
+	assert(rq != NULL);
+
+	ri = rq->ri;
+	wi = rq->wi;
+	if (ri == wi)
+		return 0;
+	else if (ri < wi)
+		return wi - ri;
+	else
+		return wi + (rq->length - ri);
+}
+
+void RingQueue_InterruptibleSleepOn(struct ring_queue *rq)
+{
+	assert(rq != NULL);
+	interruptible_sleep_on(&rq->wqh);
+}
+
+void RingQueue_WakeUpInterruptible(struct ring_queue *rq)
+{
+	assert(rq != NULL);
+	if (waitqueue_active(&rq->wqh))
+		wake_up_interruptible(&rq->wqh);
+}
+
+static void coldfire_int_irq(struct urb *urb)
+{
+	struct coldfire_t *coldfire = (struct coldfire_t *)urb->context;
+
+	static int count = 0;
+	static int old_jiffies = 0;
+
+	if (urb->actual_length > 0 || 1) {
+		printk
+		    ("irq %d data: %x status: %d interval: %d length: %d jiffies: %ld %ld ms\n",
+		     count++, coldfire->int_in_data, urb->status, urb->interval,
+		     urb->actual_length, jiffies, (jiffies - old_jiffies) * 10);
+	}
+	old_jiffies = jiffies;
+}
+
+/**
+ *	usb_stimulus_debug_data
+ */
+static inline void usb_stimulus_debug_data(const char *function, int size,
+					   const unsigned char *data)
+{
+	int i;
+
+	if (!debug)
+		return;
+
+	printk(KERN_DEBUG __FILE__ ": %s - length = %d, data = ",
+	       function, size);
+	for (i = 0; i < size; ++i) {
+		printk("%.2x ", data[i]);
+	}
+	printk("\n");
+}
+
+/**
+ *	stimulus_delete
+ */
+static inline void stimulus_delete(struct coldfire_t *coldfire)
+{
+	int i;
+
+	printk("stimulus_delete\n");
+
+	usb_stop_iso(coldfire);
+
+	if (coldfire->int_active) {
+		printk("stimulus_delete: unlink int urb\n");
+		usb_unlink_urb(coldfire->int_urb);
+		coldfire->int_active = 0;
+	}
+
+	minor_table[coldfire->minor + 0] = NULL;
+	minor_table[coldfire->minor + 1] = NULL;
+	minor_table[coldfire->minor + 2] = NULL;
+	minor_table[coldfire->minor + 3] = NULL;
+
+	kfree(coldfire->write_buffer);
+
+	kfree(coldfire->data_ioctl);
+	kfree(coldfire->data_coldfire);
+
+	usb_free_urb(coldfire->int_urb);
+	for (i = 0; i < COLDFIRE_NUMSBUF; i++) {
+		usb_free_urb(coldfire->sync_urb[i].urb);
+		kfree(coldfire->sync_urb[i].data);
+		usb_free_urb(coldfire->data_urb[i].urb);
+		kfree(coldfire->data_urb[i].data);
+	}
+
+	for (i = 0; i < STG200x_NUM_TRIGGER; i++) {
+		RingQueue_Free(&coldfire->dp[i]);
+		kfree(coldfire->trigger_buffer[i]);
+	}
+
+	kfree(coldfire);
+}
+
+/**
+ *	stimulus_open
+ */
+static int stimulus_open(struct inode *inode, struct file *file)
+{
+	struct coldfire_t *coldfire = NULL;
+	unsigned int subminor;
+	unsigned int channel;
+	int retval = 0;
+
+	dbg("%s", __FUNCTION__);
+
+	subminor = MINOR(inode->i_rdev) - USB_STIMULUS_MINOR_BASE;
+	channel = subminor & 3;
+	if ((subminor < 0) || (subminor >= MAX_DEVICES)) {
+		printk("subminor: %d\n", subminor);
+		return -ENODEV;
+	}
+
+	/* lock our minor table and get our local data for this minor */
+	down(&minor_table_mutex);
+	coldfire = minor_table[subminor];
+	if (coldfire == NULL) {
+		up(&minor_table_mutex);
+		printk("coldfire == NULL\n");
+		return -ENODEV;
+	}
+
+	/* lock this device */
+	down(&coldfire->sem);
+
+	/* unlock the minor table */
+	up(&minor_table_mutex);
+
+	printk("open coldfire: %p subminor: %d channel: %d\n",
+	       coldfire, subminor, channel);
+
+	if (coldfire->open_count[channel]) {
+		up(&coldfire->sem);
+		return -EBUSY;
+	}
+
+	if (channel == 0) {
+		coldfire->int_urb->dev = coldfire->dev;
+		printk("submit int urb\n");
+		if (usb_submit_urb(coldfire->int_urb, GFP_KERNEL)) {
+			up(&coldfire->sem);
+			printk("unable to sumbmit interrupt urb\n");
+			return -EIO;
+		}
+		coldfire->int_active = 1;
+	}
+
+	/* increment our usage count for the driver */
+	++coldfire->open_count[channel];
+	++coldfire->open_count_total;
+
+	/* save our object in the file's private structure */
+	file->private_data = coldfire;
+
+	/* unlock this device */
+	up(&coldfire->sem);
+
+	return retval;
+}
+
+/**
+ *	stimulus_release
+ */
+static int stimulus_release(struct inode *inode, struct file *file)
+{
+	struct coldfire_t *coldfire;
+	unsigned int subminor;
+	unsigned int channel;
+	int retval = 0;
+
+	coldfire = (struct coldfire_t *)file->private_data;
+	if (coldfire == NULL) {
+		dbg("%s - object is NULL", __FUNCTION__);
+		return -ENODEV;
+	}
+#if 0
+	dbg("%s - minor %d", __FUNCTION__, coldfire->minor);
+#endif
+
+	/* lock our minor table */
+	down(&minor_table_mutex);
+
+	/* lock our device */
+	down(&coldfire->sem);
+
+	subminor = MINOR(inode->i_rdev) - USB_STIMULUS_MINOR_BASE;
+	channel = subminor & 3;
+	printk("stimulus_release channel: %d\n", channel);
+
+	if (coldfire->open_count[channel] <= 0) {
+		dbg("%s - device not opened", __FUNCTION__);
+		retval = -ENODEV;
+		goto exit_not_opened;
+	}
+
+	if (coldfire->dev == NULL) {
+		/* the device was unplugged before the file was released */
+		--coldfire->open_count[channel];
+		--coldfire->open_count_total;
+		if (coldfire->open_count_total) {
+			up(&coldfire->sem);
+			up(&minor_table_mutex);
+			return 0;
+		} else {
+			up(&coldfire->sem);
+			stimulus_delete(coldfire);
+			up(&minor_table_mutex);
+			return 0;
+		}
+	}
+
+	/* decrement our usage count for the device */
+	--coldfire->open_count[channel];
+	--coldfire->open_count_total;
+	if ((coldfire->open_count[channel] <= 0) && (channel == 0)) {
+		/* shutdown any bulk writes that might be going on */
+#if 1				/* was 1 */
+		if (coldfire->int_active) {
+			printk("unlink int urb\n");
+			usb_unlink_urb(coldfire->int_urb);
+			coldfire->int_active = 0;
+		}
+#endif
+		coldfire->open_count[channel] = 0;
+	}
+
+      exit_not_opened:
+	up(&coldfire->sem);
+	up(&minor_table_mutex);
+
+	return retval;
+}
+
+/**
+ *	stimulus_poll
+ */
+static unsigned int stimulus_poll(struct file *file, poll_table * wait)
+{
+	struct coldfire_t *coldfire;
+	unsigned int mask = 0;
+	unsigned int subminor;
+	unsigned int channel;
+
+	coldfire = (struct coldfire_t *)file->private_data;
+
+	if (!COLDFIRE_IS_OPERATIONAL(coldfire))
+		return -EFAULT;
+
+#if 0
+	dbg("%s - minor %d", __FUNCTION__, coldfire->minor);
+#endif
+
+	/* lock this object */
+	down(&coldfire->sem);
+
+	subminor =
+	    MINOR(file->f_dentry->d_inode->i_rdev) - USB_STIMULUS_MINOR_BASE;
+	channel = subminor & 3;
+
+	/* verify that the device wasn't unplugged */
+	if (coldfire->dev == NULL) {
+		up(&coldfire->sem);
+		return -ENODEV;
+	}
+
+	poll_wait(file, &coldfire->dp[channel].wqh, wait);
+	if (RINGBUFFERSIZE - RingQueue_GetLength(&coldfire->dp[channel]) > 2) {
+		mask |= POLLOUT | POLLWRNORM;
+	}
+
+	/* unlock the device */
+	up(&coldfire->sem);
+
+	return mask;
+}
+
+/**
+ *	stimulus_write
+ */
+static ssize_t stimulus_write(struct file *file, const char *buffer,
+			      size_t count, loff_t * ppos)
+{
+	struct coldfire_t *coldfire;
+	ssize_t bytes_written = 0;
+	int retval = 0;
+	int space_in_ringbuffer;
+	int ret;
+
+	unsigned int subminor;
+	unsigned int channel;
+
+	coldfire = (struct coldfire_t *)file->private_data;
+
+#if 0
+	dbg("%s - minor %d, count = %d  rbum = %d", __FUNCTION__,
+	    coldfire->minor, count, channel);
+#endif
+
+	/* lock this object */
+	down(&coldfire->sem);
+
+	subminor =
+	    MINOR(file->f_dentry->d_inode->i_rdev) - USB_STIMULUS_MINOR_BASE;
+	channel = subminor & 3;
+
+	/* verify that the device wasn't unplugged */
+	if (coldfire->dev == NULL) {
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	/* verify that we actually have some data to write */
+	if (count == 0) {
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
+		goto exit;
+	}
+
+	/* we can only write as much as ringbuffer will hold */
+	space_in_ringbuffer =
+	    RINGBUFFERSIZE - RingQueue_GetLength(&coldfire->dp[channel]) - 2;
+
+	if (space_in_ringbuffer < count) {
+		bytes_written = space_in_ringbuffer;
+	} else {
+		bytes_written = count;
+	}
+
+	if (bytes_written < 0) {
+		printk("bytes written: %d x\n", bytes_written);
+	}
+
+	if (bytes_written > WRITEBUFFERSIZE)
+		bytes_written = WRITEBUFFERSIZE;
+
+	/* copy the data from userspace into our urb */
+	if (copy_from_user(coldfire->write_buffer, buffer, bytes_written)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	ret =
+	    RingQueue_Enqueue(&coldfire->dp[channel], coldfire->write_buffer,
+			      bytes_written);
+	if (ret != bytes_written) {
+		printk("failed to enqueue all bytes: %d %d\n", ret,
+		       bytes_written);
+	} else {
+#if 0
+		printk("enqueud %d bytes (%d %d)\n",
+		       bytes_written,
+		       space_in_ringbuffer,
+		       RINGBUFFERSIZE -
+		       RingQueue_GetLength(&coldfire->dp[channel]));
+#endif
+	}
+
+	retval = bytes_written;
+
+      exit:
+	/* unlock the device */
+	up(&coldfire->sem);
+
+	return retval;
+}
+
+void change_byteorder(char *data, char *data_coldfire, int elements, int *list,
+		      int size, int cmd)
+{
+	int i, j;
+	int count;
+	int inc;
+
+	count = 0;
+	for (i = 0; i < elements; i++, list++) {
+		inc = *list;
+		switch (*list) {
+		case 1:
+			*data_coldfire = *data;
+			break;
+		case 2:
+			*(data_coldfire + 0) = *(data + 1);
+			*(data_coldfire + 1) = *(data + 0);
+			break;
+		case 4:
+			*(data_coldfire + 0) = *(data + 3);
+			*(data_coldfire + 1) = *(data + 2);
+			*(data_coldfire + 2) = *(data + 1);
+			*(data_coldfire + 3) = *(data + 0);
+			break;
+		default:
+			if (*list < 0) {
+				inc = -(*list);
+				for (j = 0; j < inc; j++) {
+					*(data_coldfire + j) = *(data + j);
+				}
+			} else {
+				printk("unknown data size: %d\n", *list);
+			}
+			break;
+		}
+		data += inc;
+		data_coldfire += inc;
+		count += inc;
+	}
+
+	if (count != size) {
+		printk
+		    ("error in acu.h: count != size (%d != %d) for command cmd: %x\n",
+		     count, size, cmd);
+	}
+
+}
+
+int send_control_message(struct coldfire_t *coldfire, int cmd, char *data,
+			 int len)
+{
+	int ok;
+	int retval;
+
+	ok = 1;
+
+	if (!(len % 8)) {
+		printk("mult 8\n");
+		len++;
+	}
+
+	retval =
+	    usb_control_msg(coldfire->dev, usb_sndctrlpipe(coldfire->dev, 0),
+			    cmd, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, data, len,
+			    HZ);
+
+#if 0
+	printk("usb_control_msg: len: %d '%d,%d,%d,%d' retval: %d\n",
+	       len, *(data + 0), *(data + 1), *(data + 2), *(data + 3), retval);
+#endif
+
+	if (retval != len) {
+		printk("usb_control_msg: error: %d\n", retval);
+		ok = 0;
+	}
+
+	return ok;
+}
+
+int send_bulk_message(struct coldfire_t *coldfire, int cmd, char *data, int len)
+{
+	int ok;
+	int retval;
+
+	int16 cmd16;
+
+	ok = 1;
+
+	if (!(len % 8)) {
+		printk("mult 8\n");
+		len++;
+	}
+
+	cmd16 = cmd;
+	change_byteorder((char *)&cmd16, data, bulkcommand_elements,
+			 bulkcommand_list, 2, 0);
+
+	usb_bulk_msg(coldfire->dev, usb_sndbulkpipe(coldfire->dev, 2),
+		     data, len, &retval, HZ);
+
+#if 0
+	printk("usb_bulk_msg: len: %d '%d,%d,%d,%d' retval: %d\n",
+	       len, *(data + 0), *(data + 1), *(data + 2), *(data + 3), retval);
+#endif
+
+	if (retval != len)
+		ok = 0;
+
+	return ok;
+}
+
+int recv_control_message(struct coldfire_t *coldfire, int cmd, char *data,
+			 int len)
+{
+	int ok;
+	int retval;
+	int len_orig;
+
+	ok = 1;
+
+	len_orig = len;
+
+	if (!(len % 8)) {
+		printk("cmd:%d len %d mult 8\n", cmd, len);
+		len++;
+	}
+
+	retval =
+	    usb_control_msg(coldfire->dev, usb_rcvctrlpipe(coldfire->dev, 0),
+			    cmd, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, data, len,
+			    HZ);
+
+	if (retval != len_orig)
+		ok = 0;
+
+	printk("retval: %d len: %d\n", retval, len);
+
+	return ok;
+}
+
+/**
+ *	stimulus_ioctl
+ */
+static int stimulus_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int ok;
+	int len, retval;
+
+	struct coldfire_t *coldfire;
+
+	char *data;
+	char *data_coldfire;
+
+	coldfire = (struct coldfire_t *)file->private_data;
+
+	if (!COLDFIRE_IS_OPERATIONAL(coldfire))
+		return -EFAULT;
+
+	/* lock this object */
+	down(&coldfire->sem);
+
+	/* verify that the device wasn't unplugged */
+	if (coldfire->dev == NULL) {
+		up(&coldfire->sem);
+		return -ENODEV;
+	}
+#if 0
+	dbg("%s - minor %d, cmd 0x%.4x, arg %ld",
+	    __FUNCTION__, coldfire->minor, cmd, arg);
+#endif
+
+	/* fill in your device specific stuff here */
+
+	data = coldfire->data_ioctl;
+	data_coldfire = coldfire->data_coldfire;
+	len = -1;
+
+	ok = 0;
+	retval = 0;
+
+	switch (cmd) {
+	case ISO_STOP:
+		printk("ioctl: stop iso samples: %d\n", coldfire->sample_count);
+		usb_stop_iso(coldfire);
+		usb_set_interface(coldfire->dev, 0, 0);
+		ok = 1;
+		break;
+
+	case ISO_START:
+		printk("ioctl: start iso\n");
+		coldfire->sample_count = 0;
+		usb_set_interface(coldfire->dev, 0, 1);
+		usb_start_iso(coldfire);
+		ok = 1;
+		break;
+
+	case SET_SAMPLERATE:
+		printk("ioctl: set samplerate: %ld\n", arg);
+		len = sizeof(samplerate);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, samplerate_elements,
+				 samplerate_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SET_PROGRAM_INFO:
+		len = sizeof(programinfo);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, programinfo_elements,
+				 programinfo_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SET_CAPACITY:
+		len = sizeof(capacity);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, capacity_elements,
+				 capacity_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SETUP_TRIGGER:
+		len = sizeof(setuptrigger);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, setuptrigger_elements,
+				 setuptrigger_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		if (ok) {
+			memcpy((char *)&coldfire->triggermap, data, len);
+		}
+		break;
+
+	case SETUP_RETRIGGER_MODE:
+		len = sizeof(retrigger_mode);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, retrigger_mode_elements,
+				 retrigger_mode_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case CHANNEL_RESET:
+		len = sizeof(channelreset);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, channelreset_elements,
+				 channelreset_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case CHANNEL_DATA:
+		len = sizeof(channeldata);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, channeldata_elements,
+				 channeldata_list, len, cmd);
+		ok = send_bulk_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SYNC_RESET:
+		len = sizeof(syncoutreset);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, syncoutreset_elements,
+				 syncoutreset_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SYNC_DATA:
+		len = sizeof(syncoutdata);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, syncoutdata_elements,
+				 syncoutdata_list, len, cmd);
+		ok = send_bulk_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case COMMAND_UPLOAD:
+		len = sizeof(upload_block);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, upload_elements,
+				 upload_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case COMMAND_FLASH:
+	case COMMAND_EEPROM:
+		printk("command: %x\n", cmd);
+		len = sizeof(flash_command);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, flash_elements,
+				 flash_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case STG_START:
+	case STG_STOP:
+		printk("command start/stop: %x\n", cmd);
+		len = sizeof(startstop);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, startstop_elements,
+				 startstop_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case DISABLE_TRIGGER:
+	case ENABLE_TRIGGER:
+		printk("enable/disable trigger: %x\n", cmd);
+		len = sizeof(endistrigger);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, endistrigger_elements,
+				 endistrigger_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case STG_RESET_STATUS:
+		printk("command reset_status: %x\n", cmd);
+		len = sizeof(reset_status);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, reset_status_elements,
+				 reset_status_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SEGMENT_DEFINE:
+		printk("command segment_define: %x\n", cmd);
+		len = sizeof(segmentdef);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, segmentdef_elements,
+				 segmentdef_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SEGMENT_SELECT:
+		printk("command segment_select: %x\n", cmd);
+		len = sizeof(segmentselect);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, segmentselect_elements,
+				 segmentselect_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case SEGMENT_START:
+		printk("command segment_start: %x\n", cmd);
+		len = sizeof(segmentstart);
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		change_byteorder(data, data_coldfire, segmentstart_elements,
+				 segmentstart_list, len, cmd);
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case COMMAND_COLDSTART:
+	case COMMAND_DOWNLOADMODE:
+	case COMMAND_STREAMINGMODE:
+	case COMMAND_CONT_MODE_ON:
+	case COMMAND_CONT_MODE_OFF:
+		len = 0;
+		ok = send_control_message(coldfire, cmd, data_coldfire, len);
+		break;
+
+	case COMMAND_RESET:
+		usb_reset_device(coldfire->dev);
+		ok = 1;
+		retval = 0;
+		break;
+
+	case GET_UVAL:
+	case GET_IVAL:
+		len = sizeof(getval);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		change_byteorder(data_coldfire, data, getval_elements,
+				 getval_list, len, cmd);
+
+		if (ok) {
+#if 1
+			printk
+			    ("usb_control_msg (getval): len: %d '%lx' retval: %d\n",
+			     len, *(uint32 *) data, retval);
+#endif
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+
+		break;
+
+	case GET_IDENT:
+		len = sizeof(getident);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		change_byteorder(data_coldfire, data, getident_elements,
+				 getident_list, len, cmd);
+
+		if (ok) {
+			printk("usb_control_msg: len: %d '%lx' retval: %d\n",
+			       len, *(uint32 *) data, retval);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+
+		break;
+
+	case GET_TOTALMEM:
+	case GET_MEM:
+		len = sizeof(mem);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		change_byteorder(data_coldfire, data, mem_elements, mem_list,
+				 len, cmd);
+
+		if (ok) {
+			printk("usb_control_msg: len: %d '%lx' retval: %d\n",
+			       len, *(uint32 *) data, retval);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+
+		break;
+
+	case GET_TRIGGERMAP:
+		len = sizeof(setuptrigger);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		if (ok) {
+			change_byteorder(data_coldfire, data,
+					 setuptrigger_elements,
+					 setuptrigger_list, len, cmd);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+		break;
+
+	case GET_SAMPLERATE:
+		len = sizeof(samplerate);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		if (ok) {
+			change_byteorder(data_coldfire, data,
+					 samplerate_elements, samplerate_list,
+					 len, cmd);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+		break;
+
+	case GET_CAPACITY:
+		len = sizeof(capacity);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		if (ok) {
+			change_byteorder(data_coldfire, data,
+					 capacity_elements, capacity_list, len,
+					 cmd);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+		break;
+
+	case GET_ASCII_VERSION:
+	case GET_BUILT_DATE:
+	case GET_BUILT_TIME:
+		ok = 1;
+
+		len = 32;
+		retval =
+		    usb_control_msg(coldfire->dev,
+				    usb_rcvctrlpipe(coldfire->dev, 0), cmd,
+				    USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, data,
+				    len, HZ);
+		if (retval > len || retval < 0)
+			ok = 0;
+
+		if (ok) {
+			data[retval] = 0;
+			if (copy_to_user((char *)arg, data, retval))
+				goto error;
+		}
+
+		break;
+
+	case GET_VERSION:
+		len = sizeof(version);
+		printk("get version: len: %d\n", len);
+		ok = recv_control_message(coldfire, cmd, data_coldfire, len);
+		change_byteorder(data_coldfire, data, version_elements,
+				 version_list, len, cmd);
+
+		if (ok) {
+			printk("usb_control_msg: len: %d '%lx' retval: %d\n",
+			       len, *(uint32 *) data, retval);
+			if (copy_to_user((char *)arg, data, len))
+				goto error;
+		}
+
+		break;
+
+	case GET_PRODUCT:
+		if (coldfire->dev->descriptor.iProduct &&
+		    usb_string(coldfire->dev,
+			       coldfire->dev->descriptor.iProduct,
+			       data_coldfire, 63) > 0) {
+			if (copy_to_user((char *)arg, data_coldfire, 63))
+				goto error;
+			ok = 1;
+		}
+
+		break;
+	case GET_MANUFACTURER:
+		if (coldfire->dev->descriptor.iManufacturer &&
+		    usb_string(coldfire->dev,
+			       coldfire->dev->descriptor.iManufacturer,
+			       data_coldfire, 63) > 0) {
+			if (copy_to_user((char *)arg, data_coldfire, 63))
+				goto error;
+			ok = 1;
+		}
+
+		break;
+	case GET_SERIALNUMBER:
+		if (coldfire->dev->descriptor.iSerialNumber &&
+		    usb_string(coldfire->dev,
+			       coldfire->dev->descriptor.iSerialNumber,
+			       data_coldfire, 63) > 0) {
+			if (copy_to_user((char *)arg, data_coldfire, 63))
+				goto error;
+			ok = 1;
+		}
+
+		break;
+
+	case GET_BCDDEVICE:
+		data_coldfire[0] = ((coldfire->dev->descriptor.bcdDevice >> 12) & 0x0f) + '0';
+		data_coldfire[1] = ((coldfire->dev->descriptor.bcdDevice >> 8) & 0x0f) + '0';
+		data_coldfire[2] = '.';
+		data_coldfire[3] = ((coldfire->dev->descriptor.bcdDevice >> 4) & 0x0f) + '0';
+		data_coldfire[4] = ((coldfire->dev->descriptor.bcdDevice >> 0) & 0x0f) + '0';
+		data_coldfire[5] = 0;
+		if (copy_to_user((char *)arg, data_coldfire, 6))
+			goto error;
+		ok = 1;
+		break;
+
+	case DEBUG_CHANNELDATA:
+		len = 4;
+		if (copy_from_user(data, (char *)arg, len))
+			goto error;
+		ok = send_control_message(coldfire, cmd, data, len);
+		break;
+
+	default:
+		printk("ioctl: unknown command: %x\n", cmd);
+		break;
+	}
+
+	/* unlock the device */
+	up(&coldfire->sem);
+
+	if (ok)
+		return retval;
+
+	/* return that we did not understand this ioctl call */
+	return -ENOTTY;
+error:
+	up(&coldfire->sem);
+	return -EFAULT;
+}
+
+/**
+ *	stimulus_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
+static int stimulus_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(interface);
+	struct coldfire_t *coldfire = NULL;
+	struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int minor;
+	int i;
+	int pipe, maxp;
+	char name[10];
+
+	printk("stimulus probe called %04x %04x\n",
+	       dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	/* select a "subminor" number (part of a minor number) */
+	down(&minor_table_mutex);
+	for (minor = 0; minor < MAX_DEVICES; ++minor) {
+		if (minor_table[minor] == NULL)
+			break;
+	}
+	if (minor >= MAX_DEVICES - 3) {
+		info("Too many devices plugged in, can not handle this device.");
+		goto exit;
+	}
+
+	/* allocate memory for our device state and intialize it */
+	coldfire = kmalloc(sizeof(struct coldfire_t), GFP_KERNEL);
+	if (coldfire == NULL) {
+		err("Out of memory");
+		goto exit;
+	}
+	memset(coldfire, 0x00, sizeof(*coldfire));
+	minor_table[minor + 0] = coldfire;
+	minor_table[minor + 1] = coldfire;
+	minor_table[minor + 2] = coldfire;
+	minor_table[minor + 3] = coldfire;
+
+	init_MUTEX(&coldfire->sem);
+	coldfire->dev = dev;
+	coldfire->interface = interface;
+	coldfire->minor = minor;
+
+	memset((char *)&coldfire->triggermap, 0, sizeof(setuptrigger));
+
+	printk("search for endpoints\n");
+
+	/* set up the endpoint information */
+	/* check out the endpoints */
+	iface_desc = &interface->altsetting[1];
+	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i];
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found an interrupt in endpoint */
+			coldfire->int_in_endp = endpoint->bEndpointAddress;
+			coldfire->int_in_packet_len = endpoint->wMaxPacketSize;
+			coldfire->int_in_rate = endpoint->bInterval;
+			printk
+			    ("found int in endpoint (ep: %d len: %d rate: %d)\n",
+			     coldfire->int_in_endp, coldfire->int_in_packet_len,
+			     coldfire->int_in_rate);
+
+		}
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x01)) {
+			/* we found an iso in endpoint */
+			coldfire->iso_in_endp = endpoint->bEndpointAddress;
+			coldfire->iso_in_packet_len = endpoint->wMaxPacketSize;
+			printk("found iso in endpoint (ep: %d len: %d)\n",
+			       coldfire->iso_in_endp,
+			       coldfire->iso_in_packet_len);
+
+			if (coldfire->iso_in_packet_len != 3 * 4 + 16) {
+				printk
+				    ("Warning: iso_in_packet_len != 3*4: %d, not a sync iso endpoint\n",
+				     coldfire->iso_in_packet_len);
+			}
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x01)) {
+			/* we found an iso out endpoint */
+			coldfire->iso_out_endp = endpoint->bEndpointAddress;
+			coldfire->iso_out_packet_len = endpoint->wMaxPacketSize;
+			printk("found iso out endpoint (ep: %d len: %d)\n",
+			       coldfire->iso_out_endp,
+			       coldfire->iso_out_packet_len);
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found an bulk out endpoint */
+			coldfire->bulk_out_endp = endpoint->bEndpointAddress;
+			coldfire->bulk_out_packet_len =
+			    endpoint->wMaxPacketSize;
+			printk("found bulk out endpoint (ep: %d len: %d)\n",
+			       coldfire->bulk_out_endp,
+			       coldfire->bulk_out_packet_len);
+		}
+
+	}
+
+	/* initialize the devfs node for this device and register it */
+	sprintf(name, "stimulus%d", coldfire->minor);
+
+	coldfire->remove_pending = 0;
+	coldfire->last_error = 0;
+
+	coldfire->data_ioctl = kmalloc(4 * 1024, GFP_KERNEL);
+	coldfire->data_coldfire = kmalloc(4 * 1024, GFP_KERNEL);
+
+	coldfire->write_buffer = kmalloc(WRITEBUFFERSIZE, GFP_KERNEL);
+
+	/* init int transfer */
+
+	pipe = usb_rcvintpipe(coldfire->dev, coldfire->int_in_endp);
+	maxp = usb_maxpacket(coldfire->dev, pipe, usb_pipeout(pipe));
+	printk("pipe: %x %x\n", pipe, maxp);
+
+	printk("fill int urb: rate: %d\n", coldfire->int_in_rate);
+
+	coldfire->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!coldfire->int_urb)
+		return -ENOMEM;
+	usb_fill_int_urb(coldfire->int_urb,
+			 coldfire->dev, pipe,
+			 &coldfire->int_in_data,
+			 coldfire->int_in_packet_len,
+			 coldfire_int_irq, coldfire, coldfire->int_in_rate);
+
+#if 0
+	printk("submit in urb\n");
+	if (usb_submit_urb(coldfire->int_urb, GFP_KERNEL)) {
+		printk("unable to submit URB\n");
+	}
+#endif
+
+	for (i = 0; i < STG200x_NUM_TRIGGER; i++) {
+		RingQueue_Allocate(&coldfire->dp[i], RINGBUFFERSIZE);
+		RingQueue_Initialize(&coldfire->dp[i]);
+		coldfire->trigger_buffer[i] =
+		    kmalloc(1023 * 2 * (STG200x_NUM_CHANNELS + 1), GFP_KERNEL);
+	}
+
+	for (i = 0; i < COLDFIRE_NUMSBUF; i++) {
+		coldfire->sync_urb[i].urb =
+		    usb_alloc_urb(SYNCFRAMES, GFP_KERNEL);
+		coldfire->sync_urb[i].data =
+		    kmalloc(SYNCFRAMES * SYNC_PACKET_SIZE, GFP_KERNEL);
+		if (coldfire->sync_urb[i].urb == NULL) {
+			err("usb_alloc_urb(%d.) failed.", SYNCFRAMES);
+			//                coldfire->uvd_used = 0;
+			goto error;
+		}
+
+		coldfire->data_urb[i].urb =
+		    usb_alloc_urb(DESCFRAMES, GFP_KERNEL);
+		coldfire->data_urb[i].data =
+		    kmalloc(DESCFRAMES * coldfire->iso_out_packet_len,
+			    GFP_KERNEL);
+		printk("data urb buffer: %p len: %d\n",
+		       coldfire->data_urb[i].data,
+		       DESCFRAMES * coldfire->iso_out_packet_len);
+		if (coldfire->data_urb[i].urb == NULL) {
+			err("usb_alloc_urb(%d.) failed.", DESCFRAMES);
+			//                coldfire->uvd_used = 0;
+			goto error;
+		}
+
+	}
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, coldfire);
+
+	/* let the user know what node this device is now attached to */
+	info("USB Skeleton device now attached to USBStimulus%d",
+	     coldfire->minor);
+	goto exit;
+
+      error:
+	stimulus_delete(coldfire);
+	coldfire = NULL;
+
+      exit:
+	up(&minor_table_mutex);
+	return 0;
+}
+
+/**
+ *	stimulus_disconnect
+ *
+ *	Called by the usb core when the device is removed from the system.
+ */
+static void stimulus_disconnect(struct usb_interface *interface)
+{
+	struct coldfire_t *coldfire;
+	int minor;
+
+	coldfire = usb_get_intfdata(interface);
+
+	printk("stimulus_disconnect\n");
+
+	down(&minor_table_mutex);
+	down(&coldfire->sem);
+
+	coldfire->remove_pending = 1;
+
+	minor = coldfire->minor;
+
+#if 0
+	printk("unlink int urb\n");
+	usb_unlink_urb(coldfire->int_urb);
+#endif
+
+	/* if the device is not opened, then we clean up right now */
+	if (!coldfire->open_count_total) {
+		up(&coldfire->sem);
+		stimulus_delete(coldfire);
+	} else {
+		usb_stop_iso(coldfire);
+		if (coldfire->int_active) {
+			printk("stimulus disconnect: usb_unlink_urb\n");
+			usb_unlink_urb(coldfire->int_urb);
+			coldfire->int_active = 0;
+		}
+		coldfire->dev = NULL;
+		up(&coldfire->sem);
+	}
+
+	info("USB Stimulus #%d now disconnected", minor);
+	up(&minor_table_mutex);
+}
+
+/**
+ *	usb_stimulus_init
+ */
+static int __init usb_stimulus_init(void)
+{
+	int result;
+
+	printk("sizeof int: %d sizeof long: %d\n", sizeof(int), sizeof(long));
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&stimulus_driver);
+	if (result < 0) {
+		err("usb_register failed for the " __FILE__
+		    " driver. Error number %d", result);
+		return -1;
+	}
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+/**
+ *	usb_stimulus_exit
+ */
+static void __exit usb_stimulus_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&stimulus_driver);
+}
+
+module_init(usb_stimulus_init);
+module_exit(usb_stimulus_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+int usb_stop_iso(struct coldfire_t *coldfire)
+{
+	static const char proc[] = "usb_stop_iso";
+	int i, j, n;
+
+	printk("usb_stop_iso called\n");
+
+	if ((coldfire == NULL) || (!coldfire->streaming)
+	    || (coldfire->dev == NULL))
+		return 0;
+
+	printk("usb_stop_iso\n");
+
+	for (i = 0; i < COLDFIRE_NUMSBUF; i++) {
+		j = usb_unlink_urb(coldfire->sync_urb[i].urb);
+		if (j < 0)
+			err("%s: usb_unlink_urb() error %d.", proc, j);
+
+		j = usb_unlink_urb(coldfire->data_urb[i].urb);
+		if (j < 0)
+			err("%s: usb_unlink_urb() error %d.", proc, j);
+	}
+
+	for (i = 0; i < STG200x_NUM_TRIGGER; i++) {
+		n = RingQueue_GetLength(&coldfire->dp[i]);
+		RING_QUEUE_DEQUEUE_BYTES(&coldfire->dp[i], n);
+	}
+
+	coldfire->streaming = 0;
+
+	return 0;
+}
+
+int usb_start_iso(struct coldfire_t *coldfire)
+{
+	static const char proc[] = "coldfire_StartDataPump";
+	struct usb_device *dev = coldfire->dev;
+	int i, errFlag;
+
+	if (!COLDFIRE_IS_OPERATIONAL(coldfire)) {
+		err("%s: Coldfire is not operational", proc);
+		return -EFAULT;
+	}
+
+	coldfire->freqn = ((STG200x_MAX_SAMPLERATE << 11) + 62) / 125;	/* shift the samplerate per ms to bits 14..23 */
+	coldfire->freqmax = coldfire->freqn + (coldfire->freqn >> 2);
+	for (i = 0; i < STG200x_NUM_TRIGGER; i++) {
+		coldfire->freqm[i] = coldfire->freqn;
+		coldfire->phase[i] = 0;
+	}
+
+	for (i = 0; i < COLDFIRE_NUMSBUF; i++) {
+		struct urb *urb = coldfire->sync_urb[i].urb;
+		urb->dev = dev;
+		urb->context = coldfire;
+		urb->pipe = usb_rcvisocpipe(dev, coldfire->iso_in_endp);
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = coldfire->sync_urb[i].data;
+		urb->complete = usbout_sync_completed;
+		urb->number_of_packets = SYNCFRAMES;
+		urb->transfer_buffer_length = SYNCFRAMES * SYNC_PACKET_SIZE;
+		urb->next = 0;
+
+		usbout_sync_prepare_desc(coldfire, urb);
+
+		urb = coldfire->data_urb[i].urb;
+		urb->dev = dev;
+		urb->context = coldfire;
+		urb->pipe = usb_sndisocpipe(dev, coldfire->iso_out_endp);
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = coldfire->data_urb[i].data;
+		urb->complete = usbout_completed;
+		urb->number_of_packets = DESCFRAMES;
+		urb->transfer_buffer_length =
+		    DESCFRAMES * coldfire->iso_out_packet_len;
+		urb->next = NULL;
+
+		usbout_prepare_desc(coldfire, urb);
+	}
+
+	/* Submit all URBs */
+	for (i = 0; i < COLDFIRE_NUMSBUF; i++) {
+		errFlag = usb_submit_urb(coldfire->sync_urb[i].urb, GFP_KERNEL);
+		if (errFlag)
+			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
+
+		errFlag = usb_submit_urb(coldfire->data_urb[i].urb, GFP_KERNEL);
+		if (errFlag)
+			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
+	}
+
+	coldfire->streaming = 1;
+
+	return 0;
+
+}
+
+static int usbout_sync_prepare_desc(struct coldfire_t *coldfire,
+				    struct urb *urb)
+{
+	unsigned int i, offs;
+
+	for (i = offs = 0; i < SYNCFRAMES; i++, offs += SYNC_PACKET_SIZE) {
+		urb->iso_frame_desc[i].length = SYNC_PACKET_SIZE;
+		urb->iso_frame_desc[i].offset = offs;
+	}
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_sync_retire_desc(struct coldfire_t *coldfire, struct urb *urb)
+{
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned int f[STG200x_NUM_TRIGGER], i, j;
+	static unsigned int f_old[STG200x_NUM_TRIGGER];
+	unsigned rb_size[STG200x_NUM_TRIGGER];
+	static int max_wait[STG200x_NUM_TRIGGER];
+
+	for (i = 0; i < SYNCFRAMES; i++, cp += SYNC_PACKET_SIZE) {
+		if (urb->iso_frame_desc[i].status) {
+			dprintk((KERN_DEBUG
+				 "usbout_sync_retire_desc: frame %u status %d\n",
+				 i, urb->iso_frame_desc[i].status));
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length < SYNC_PACKET_SIZE) {
+			dprintk((KERN_DEBUG
+				 "usbout_sync_retire_desc: frame %u length %d\n",
+				 i, urb->iso_frame_desc[i].actual_length));
+			continue;
+		}
+		for (j = 0; j < STG200x_NUM_TRIGGER; j++) {
+			f[j] =
+			    cp[j * 3 +
+			       0] | (cp[j * 3 + 1] << 8) | (cp[j * 3 +
+							       2] << 16);
+		}
+		for (j = 0; j < STG200x_NUM_TRIGGER; j++) {
+			rb_size[j] =
+			    cp[j * 4 +
+			       12] | (cp[j * 4 + 13] << 8) | (cp[j * 4 +
+								 14] << 16) |
+			    (cp[j * 4 + 15] << 24);
+		}
+#if 0
+		if (abs(f - coldfire->freqn) > (coldfire->freqn >> 3)
+		    || f > coldfire->freqmax) {
+			printk(KERN_WARNING
+			       "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n",
+			       f, coldfire->freqn);
+			continue;
+		}
+#endif
+		for (j = 0; j < STG200x_NUM_TRIGGER; j++) {
+#if 1
+			max_wait[j]++;
+			if (f_old[j] != f[j] || max_wait[j] == 100) {
+				max_wait[j] = 0;
+				printk
+				    ("new value for freq[%d]: old: %d new: %d diff: %d freq: %d frac: %x full: %x phase: %x\n",
+				     j, coldfire->freqm[j], f[j],
+				     coldfire->freqm[j] - f[j], f[j] >> 14,
+				     (f[j] & 0x3fff), rb_size[j],
+				     coldfire->phase[j]);
+				f_old[j] = f[j];
+			}
+#endif
+
+			coldfire->freqm[j] = f[j];
+		}
+	}
+	return 0;
+}
+
+static void usbout_sync_completed(struct urb *urb)
+{
+	//    unsigned long flags;
+	struct coldfire_t *coldfire = (struct coldfire_t *)urb->context;
+	int suret = 0;
+
+	if (!COLDFIRE_IS_OPERATIONAL(coldfire))
+		return;
+	if (!coldfire->streaming) {
+		//        info ("not streaming, but interrupt!\n");
+		return;
+	}
+#if 0
+	printk(KERN_DEBUG
+	       "usbout_sync_completed: status %d errcnt %d flags 0x%x\n",
+	       urb->status, urb->error_count, u->flags);
+#endif
+
+	urb->dev = coldfire->dev;
+	//      spin_lock_irqsave(&coldfire->lock, flags);
+	usbout_sync_retire_desc(coldfire, urb);
+	usbout_sync_prepare_desc(coldfire, urb);
+	if ((suret = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
+		dprintk((KERN_DEBUG
+			 "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n",
+			 suret));
+	}
+	//      spin_unlock_irqrestore(&coldfire->lock, flags);
+}
+
+static int usbout_prepare_desc(struct coldfire_t *coldfire, struct urb *urb)
+{
+	unsigned int i, j;
+	unsigned int cnt, acnt, offs;
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned int scnt[STG200x_NUM_TRIGGER];
+
+	for (i = offs = 0; i < urb->number_of_packets; i++) {
+		for (j = 0; j < STG200x_NUM_TRIGGER; j++) {
+			coldfire->phase[j] =
+			    (coldfire->phase[j] & 0x3fff) + coldfire->freqm[j];
+			scnt[j] = coldfire->phase[j] >> 14;
+		}
+
+		acnt = copy_samples(coldfire, cp, scnt);
+		cnt = acnt * STG200x_BYTES_PER_SAMPLE;
+
+		urb->iso_frame_desc[i].offset = offs;
+		urb->iso_frame_desc[i].length = cnt;
+
+		offs += cnt;
+		cp += cnt;
+	}
+
+	return 0;
+}
+
+static int usbout_retire_desc(struct coldfire_t *coldfire, struct urb *urb)
+{
+	unsigned int i;
+	static int last_frame = 0;
+
+	for (i = 0; i < DESCFRAMES; i++) {
+		if (urb->iso_frame_desc[i].status) {
+			dprintk((KERN_DEBUG
+				 "usbout_retire_desc: frame %u status %d\n", i,
+				 urb->iso_frame_desc[i].status));
+			continue;
+		}
+	}
+
+	if (last_frame != urb->start_frame) {
+		printk("start frame: ist: %d soll: %d\n", urb->start_frame,
+		       last_frame);
+	}
+	last_frame = (urb->start_frame + DESCFRAMES) & 0x3ff;
+
+	return 0;
+}
+
+static void usbout_completed(struct urb *urb)
+{
+	//    unsigned long flags;
+	struct coldfire_t *coldfire = (struct coldfire_t *)urb->context;
+	int suret = 0;
+
+	if (!COLDFIRE_IS_OPERATIONAL(coldfire))
+		return;
+	if (!coldfire->streaming) {
+		//        info ("not streaming, but interrupt!\n");
+		return;
+	}
+#if 0
+	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n",
+	       urb->status, urb->error_count, u->flags);
+#endif
+	urb->dev = coldfire->dev;
+	//      spin_lock_irqsave(&coldfire->lock, flags);
+
+	usbout_retire_desc(coldfire, urb);
+	usbout_prepare_desc(coldfire, urb);
+
+	if ((suret = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
+		dprintk((KERN_DEBUG
+			 "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n",
+			 suret));
+	}
+	//      spin_unlock_irqrestore(&coldfire->lock, flags);
+}
+
+/*
+  copy data from the ringbuffers to usb packets
+   this function mixes the data from the different trigger queues to
+   one usb endpoint
+
+   demuxing is done in the coldfire
+*/
+
+static int copy_samples(struct coldfire_t *coldfire, unsigned char *dest,
+			int *num)
+{
+	static int packet = 0;
+
+	static int bytepos[STG200x_NUM_TRIGGER] = { 0, 0, 2, 2 };
+	static int bitpos[STG200x_NUM_TRIGGER] = { 6, 7, 6, 7 };
+
+	static int syncout_bytepos[4] = { 4, 4, 6, 6 };
+	static int syncout_bitpos[4] = { 6, 7, 6, 7 };
+
+	static int digout_bytepos[8] = { 8, 8, 10, 10, 12, 12, 14, 14 };
+	static int digout_bitpos[8] = { 6, 7, 6, 7, 6, 7, 6, 7 };
+
+	unsigned int i, j;
+	unsigned int trigger;
+
+	unsigned int samples[STG200x_NUM_TRIGGER];
+	unsigned int n[STG200x_NUM_TRIGGER];
+	uint16 *tp[STG200x_NUM_TRIGGER];
+
+	unsigned char hb, lb;
+
+	int max_samples;
+
+	max_samples = 0;
+
+	for (trigger = 0; trigger < STG200x_NUM_TRIGGER; trigger++) {
+		n[trigger] =
+		    RingQueue_GetLength(&coldfire->dp[trigger]) / (2 *
+								   (STG200x_NUM_CHANNELS
+								    + 1));
+
+		if (num[trigger] * STG200x_BYTES_PER_SAMPLE >
+		    coldfire->iso_out_packet_len) {
+			printk("trigger: %d num too big: %d %d\n", trigger,
+			       num[trigger],
+			       coldfire->iso_out_packet_len /
+			       STG200x_BYTES_PER_SAMPLE);
+			num[trigger] =
+			    coldfire->iso_out_packet_len /
+			    STG200x_BYTES_PER_SAMPLE;
+		}
+
+#if 0
+		printk("%d: %d %d  ", trigger, num[trigger], n[trigger]);
+#endif
+
+		samples[trigger] = num[trigger];
+		if (num[trigger] > n[trigger]) {
+#if 0
+			if (trigger == 0 || trigger == 1) {
+				printk
+				    ("warning: ringbuffer trigger %d empty: num %d n: %d\n",
+				     trigger, num[trigger], n[trigger]);
+			}
+#endif
+			samples[trigger] = n[trigger];
+		}
+
+		if (samples[trigger] > max_samples) {
+			max_samples = samples[trigger];
+		}
+	}
+
+#if 0
+	printk("\n");
+#endif
+	if (!max_samples) {
+		memset(dest, 0, STG200x_BYTES_PER_SAMPLE);
+		return 1;
+	}
+
+	memset(dest, 0, STG200x_BYTES_PER_SAMPLE * max_samples);
+
+	/* Es werden 16 Bytes (8 Kanaele je 16 bit) je sample geschickt */
+
+	for (trigger = 0; trigger < STG200x_NUM_TRIGGER; trigger++) {
+		RingQueue_Dequeue(&coldfire->dp[trigger],
+				  (unsigned char *)coldfire->
+				  trigger_buffer[trigger],
+				  2 * samples[trigger] * (STG200x_NUM_CHANNELS +
+							  1));
+		tp[trigger] = coldfire->trigger_buffer[trigger];
+		if (samples[trigger]) {
+			RingQueue_WakeUpInterruptible(&coldfire->dp[trigger]);
+		}
+	}
+
+	for (i = 0; i < max_samples; i++, dest += STG200x_BYTES_PER_SAMPLE) {
+		for (trigger = 0; trigger < STG200x_NUM_TRIGGER; trigger++) {
+
+			if (samples[trigger] == 0)
+				continue;
+			samples[trigger]--;
+
+			/* include this trigger in the usb packet */
+			*(unsigned short *)(dest + bytepos[trigger]) |=
+			    (1 << bitpos[trigger]);
+
+			for (j = 0; j < STG200x_NUM_CHANNELS; j++) {	// all channels
+				*tp[trigger] &= 0x1fff;
+
+				if (coldfire->triggermap.
+				    channelmap[trigger] & (1 << j)) {
+					hb = (*tp[trigger]) >> 8;
+					lb = (*tp[trigger]) & 0xff;
+					*(unsigned short *)(dest + (j << 1)) |=
+					    ((lb << 8) + hb);
+				}
+				tp[trigger]++;
+			}
+
+#if 1
+			if (coldfire->triggermap.digoutmap[trigger]) {
+				for (j = 0; j < 8; j++) {
+					if (*tp[trigger] & (1 << (8 + j))) {
+						*(unsigned short *)(dest +
+								    digout_bytepos
+								    [j]) |=
+						    (1 << digout_bitpos[j]);
+					}
+				}
+			}
+
+			if (coldfire->triggermap.syncmap[trigger]) {
+				for (j = 0; j < 4; j++) {
+					if (*tp[trigger] & (1 << j)) {
+						*(unsigned short *)(dest +
+								    syncout_bytepos
+								    [j]) |=
+						    (1 << syncout_bitpos[j]);
+					}
+				}
+			}
+#endif
+
+			tp[trigger]++;
+
+		}		/* trigger */
+		packet++;
+	}			/* samples (i) */
+
+	coldfire->sample_count += max_samples;
+
+	return max_samples;
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.