--- 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 (greg@kroah.com) + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}