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;
+}