Commit cb370ad5 authored by Evangelia Gousiou's avatar Evangelia Gousiou

last version of fmctdc1ns5cha calibration modules

parent 02101201
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>
MODULE_INFO(vermagic, VERMAGIC_STRING);
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};
static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
{ 0x35ec255d, "module_layout" },
{ 0x1976aa06, "param_ops_bool" },
{ 0x3539443, "usb_serial_deregister_drivers" },
{ 0xdf6a71a4, "usb_serial_register_drivers" },
{ 0x73c9cdb0, "usb_serial_generic_open" },
{ 0x6143a69d, "dev_warn" },
{ 0x53662107, "tty_encode_baud_rate" },
{ 0x6339a8bc, "mutex_unlock" },
{ 0xcf510c4a, "mutex_lock" },
{ 0x41b8c132, "usb_serial_generic_close" },
{ 0xcea0a119, "kmalloc_caches" },
{ 0x41ad0272, "kmem_cache_alloc_trace" },
{ 0xd44c22ec, "usb_reset_device" },
{ 0x93d085b2, "dev_set_drvdata" },
{ 0x50eedeb8, "printk" },
{ 0x37a0cba, "kfree" },
{ 0x64d0da33, "usb_control_msg" },
{ 0x12da5bb2, "__kmalloc" },
{ 0x35af9caf, "dev_err" },
{ 0xddffa24, "dev_get_drvdata" },
{ 0xb4390f9a, "mcount" },
};
static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=usbserial";
MODULE_ALIAS("usb:v045Bp0053d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0471p066Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0489pE000d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0489pE003d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0745p1000d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v08E6p5501d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v08FDp000Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0BEDp1100d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0BEDp1101d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0FCFp1003d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0FCFp1004d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v0FCFp1006d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10A6pAA26d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10ABp10C5d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10B5pAC70d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p0F91d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p1101d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p1601d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p800Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p803Bd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8044d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p804Ed*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8053d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8054d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8066d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p806Fd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p807Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p80CAd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p80DDd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p80F6d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8115d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p813Dd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p813Fd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p814Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p814Bd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8156d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p815Ed*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p818Bd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p819Fd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81A6d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81A9d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81ACd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81ADd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81C8d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81E2d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81E7d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81E8d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p81F2d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8218d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p822Bd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p826Bd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8293d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p82F9d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8341d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8382d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p83A8d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p83D8d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8411d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8418d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p846Ed*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8477d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p85EAd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p85EBd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8664d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4p8665d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pEA60d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pEA61d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pEA70d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pEA80d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pEA71d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pF001d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pF002d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pF003d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C4pF004d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10C5pEA61d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v10CEpEA6Ad*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v13ADp9999d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v1555p0004d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v166Ap0303d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v16D6p0001d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v16DCp0010d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v16DCp0011d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v16DCp0012d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v16DCp0015d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v17A8p0001d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v17A8p0005d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v17F4pAAAAd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v1843p0200d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v18EFpE00Fd*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v1BE3p07A6d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v3195pF190d*dc*dsc*dp*ic*isc*ip*");
MODULE_ALIAS("usb:v413Cp9500d*dc*dsc*dp*ic*isc*ip*");
MODULE_INFO(srcversion, "FF7E88FED57F3623F48F6A3");
......@@ -32,6 +32,12 @@ default_test_syntax = r'(test)?(\d\d)'
original_raw_input = raw_input
sys.path.append('gnurabbit/python/')
sys.path.append('common/')
sys.path.append('common/usb_box')
sys.path.append('common/cp210x')
sys.path.append('test/fmceeprom/python')
def pts_raw_input(msg, default='y'):
try:
ret = original_raw_input(msg)
......
ifneq ($(KERNELRELEASE),)
obj-m := usbtmc.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
// usbtmc.c
// Linux kernel module for USBTMC (USB Test and Measurement Class) devices
// Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
// See revision history at the end of this file
//
// 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 program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available at
// http://www.gnu.org/copyleft/gpl.html.
// #define USBTMC_DEBUG
// If defined: causes the driver to log status messages in the kernel log
#define USBTMC_VERSION 110
// Integer representation of version code (1.1)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include "usbtmc.h"
#include <linux/slab.h>
static struct usb_device_id usbtmc_devices[] = {
{.match_flags=USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
// Device class and sub class need to match for notification by the
// usb core layer.
.bInterfaceClass=254, // 254 = application specific
.bInterfaceSubClass=3}, // 3 = test and measurement class (USBTMC)
{ } // Empty (terminating) entry
};
// This list defines which devices are serviced by this driver. This driver
// handles USBTMC devices, so we look for the corresponding class (application
// specific) and subclass (USBTMC).
static dev_t dev;
// Will hold base (first) major/minor number to be used.
// The major number used is allocated dynamically in usbtmc_init.
static struct cdev cdev;
// Character device structure for minor number 0 (for communication with
// the driver itself, not an instrument.
static u8 usbtmc_minors[USBTMC_MINOR_NUMBERS];
// This array is used to track the status of the minor numbers allocated by
// the driver (used or unused).
// 0=unused; 1=used.
// Minor number 0 is reserved for communication with the driver itself.
static struct usbtmc_device_data *usbtmc_devs[USBTMC_MINOR_NUMBERS];
// This array will hold the private data pointers of the instruments. It is
// used by the minor 0 driver to get access to the USB sessions to retrieve
// instrument information.
struct usbtmc_device_data {
struct cdev cdev;
int devno;
struct usb_interface *intf;
const struct usb_device_id *id;
unsigned int bulk_in;
unsigned int bulk_out;
u8 bTag;
struct usb_device *usb_dev;
u8 eof;
char __user *retry_buf;
size_t retry_count;
int timeout;
u8 term_char_enabled;
u8 term_char;
int fread;
int auto_abort;
int add_nl_on_read;
int rem_nl_on_write;
};
// This structure holds private data for each USBTMC device. One copy is
// allocated for each USBTMC device in the driver's probe function.
static struct usb_driver usbtmc_driver;
// This structure contains registration information for the driver. The
// information is passed to the system through usb_register(), called in the
// driver's init function.
static u8 *usbtmc_buffer;
// Pointer to buffer for I/O data (allocated in usbtmc_init)
static u8 usbtmc_last_write_bTag;
static u8 usbtmc_last_read_bTag;
// Last bTag values (needed for abort)
// static struct completion usbtmc_init_done;
// "Completion" for driver initialization....
// Forward declarations
int usbtmc_ioctl_abort_bulk_in (struct inode *,struct file *,unsigned int,
unsigned long);
int usbtmc_ioctl_abort_bulk_out (struct inode *,struct file *,unsigned int,
unsigned long);
int usbtmc_open(struct inode *inode,struct file *filp)
// This function is called when opening an instrument device file. It looks for
// the device's USB endpoints for later access.
{
struct usbtmc_device_data *p_device_data;
u8 n;
u8 bulk_in,bulk_out;
struct usb_host_interface *curr_setting;
struct usb_endpoint_descriptor *end_point;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_open called\n");
#endif
if(!iminor(inode)) goto minor_null; // Driver communication
// Get pointer to instrument's private data
p_device_data = container_of(inode->i_cdev,struct usbtmc_device_data,cdev);
// Store pointer in file structure's private data field
filp->private_data=p_device_data;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Number of USB settings is %u\n",
p_device_data->intf->num_altsetting);
#endif
// USBTMC devices have only one setting, so use that (current setting)
curr_setting=p_device_data->intf->cur_altsetting;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Number of endpoints is %u\n",
curr_setting->desc.bNumEndpoints);
#endif
// Find bulk in endpoint
bulk_in=0;
for(n=0;n<(curr_setting->desc.bNumEndpoints);n++) {
end_point=&(curr_setting->endpoint[n].desc);
if((end_point->bEndpointAddress & USB_DIR_IN) &&
((end_point->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==
USB_ENDPOINT_XFER_BULK)) {
bulk_in=end_point->bEndpointAddress;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Found bulk in endpoint at %u\n",
bulk_in);
#endif
n=curr_setting->desc.bNumEndpoints; // Exit loop
}
}
p_device_data->bulk_in=bulk_in;
// Find bulk out endpoint
bulk_out=0;
for(n=0;n<(curr_setting->desc.bNumEndpoints);n++) {
end_point=&(curr_setting->endpoint[n].desc);
if(!(end_point->bEndpointAddress & USB_DIR_IN) &&
((end_point->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==
USB_ENDPOINT_XFER_BULK)) {
bulk_out=end_point->bEndpointAddress;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Found Bulk out endpoint at %u\n",
bulk_out);
#endif
n=curr_setting->desc.bNumEndpoints; // Exit loop
}
}
p_device_data->bulk_out=bulk_out;
return 0;
minor_null:
// Minor number 0 is reserved for communication with driver
// Allocate memory for private data
if(!(p_device_data=kmalloc(sizeof(struct usbtmc_device_data),GFP_KERNEL))) {
printk(KERN_ALERT "USBTMC: Unable to allocate kernel memory\n");
return -ENOMEM;
}
// Set major/minor to 0
p_device_data->devno=0;
// Store pointer in file structure's private data field
filp->private_data=p_device_data;
return 0;
}
int usbtmc_release(struct inode *inode,struct file *filp)
// This function is called when closing the instrument device file.
{
#ifdef USBTMC_DEBUG
printk(KERN_ALERT "USBTMC: usbtmc_release called\n");
#endif
if(!iminor(inode)) goto minor_null; // Driver communication
return 0;
minor_null:
// Minor number 0 is reserved for communication with driver
// Free buffer allocated in usbtmc_init
kfree(filp->private_data);
return 0;
}
int usbtmc_buffer_append(char *dest,char *src,int *count)
// Helper function for usbtmc_read.
{
int n=0;
while(*src!=0){ // Continue to the end of source string
*dest=*src;
dest++;
src++;
n++;
(*count)++;
}
return n;
}
ssize_t usbtmc_read(struct file *filp,
char __user *buf,
size_t count,
loff_t *f_pos)
// This function reads the instrument's output buffer through a
// USMTMC DEV_DEP_MSG_IN message.
{
struct usbtmc_device_data *p_device_data;
unsigned int pipe;
int retval;
int actual;
unsigned long int n_characters;
struct usb_device *p_device;
int n;
char *p;
char *s;
int t;
int remaining;
int done;
int this_part;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_read called\n");
printk(KERN_NOTICE "USBTMC: Count is %u\n",count);
#endif
// Get pointer to private data structure
p_device_data=filp->private_data;
if(!p_device_data->devno) goto minor_null; // Driver communication
if((p_device_data->fread)&&(p_device_data->eof)) {
// Zero will tell fread that the EOF was reached. It will keep fread
// from retrying to read up to the max number of characters.
p_device_data->eof=0;
return 0;
}
remaining=count;
done=0;
while(remaining>0)
{
if(remaining>USBTMC_SIZE_IOBUFFER-12-3) {
this_part=USBTMC_SIZE_IOBUFFER-12-3;
}
else {
this_part=remaining;
}
// Setup IO buffer for DEV_DEP_MSG_IN message
usbtmc_buffer[0]=2; // REQUEST_DEV_DEP_MSG_IN
usbtmc_buffer[1]=p_device_data->bTag; // Transfer ID (bTag)
usbtmc_buffer[2]=~(p_device_data->bTag); // Inverse of bTag
usbtmc_buffer[3]=0; // Reserved
usbtmc_buffer[4]=(this_part-12-3)&255; // Max transfer (first byte)
usbtmc_buffer[5]=((this_part-12-3)>>8)&255; // Second byte
usbtmc_buffer[6]=((this_part-12-3)>>16)&255; // Third byte
usbtmc_buffer[7]=((this_part-12-3)>>24)&255; // Fourth byte
usbtmc_buffer[8]=p_device_data->term_char_enabled*2;
// Use term character?
usbtmc_buffer[9]=p_device_data->term_char; // Term character
usbtmc_buffer[10]=0; // Reserved
usbtmc_buffer[11]=0; // Reserved
// Create pipe for bulk out transfer
pipe=usb_sndbulkpipe(p_device_data->usb_dev,p_device_data->bulk_out);
// Send bulk URB
retval=usb_bulk_msg(p_device_data->usb_dev,pipe,usbtmc_buffer,12,
&actual,p_device_data->timeout);
// Store bTag (in case we need to abort)
usbtmc_last_write_bTag=p_device_data->bTag;
// Increment bTag -- and increment again if zero
(p_device_data->bTag)++;
if(!(p_device_data->bTag)) (p_device_data->bTag)++;
if(retval<0) {
printk(KERN_NOTICE "USBTMC: usb_bulk_msg returned %d\n",
retval);
if(p_device_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(0,filp,USBTMC_IOCTL_ABORT_BULK_OUT,
0);
return retval;
}
// Create pipe for bulk in transfer
pipe=usb_rcvbulkpipe(p_device_data->usb_dev,p_device_data->bulk_in);
// Send bulk URB
retval=usb_bulk_msg(p_device_data->usb_dev,pipe,usbtmc_buffer,
USBTMC_SIZE_IOBUFFER,&actual,p_device_data->timeout);
// Store bTag (in case we need to abort)
usbtmc_last_read_bTag=p_device_data->bTag;
if(retval<0) {
printk(KERN_NOTICE "USBTMC: Unable to read data, error %d\n",
retval);
if(p_device_data->auto_abort)
usbtmc_ioctl_abort_bulk_in(0,filp,USBTMC_IOCTL_ABORT_BULK_IN,0);
return retval;
}
// How many characters did the instrument send?
n_characters=usbtmc_buffer[4]+
(usbtmc_buffer[5]<<8)+
(usbtmc_buffer[6]<<16)+
(usbtmc_buffer[7]<<24);
// Copy buffer to user space
if(copy_to_user(buf+done,&usbtmc_buffer[12],n_characters)) {
// There must have been an addressing problem
return -EFAULT;
}
done+=n_characters;
if(n_characters<USBTMC_SIZE_IOBUFFER) remaining=0;
}
if(p_device_data->add_nl_on_read==USBTMC_ATTRIB_VAL_ON) {
// Add newline character
if(done<count) { // Still space in user buffer?
usbtmc_buffer[0]='\n';
if(copy_to_user(buf+done,&usbtmc_buffer[0],1)) {
// There must have been an addressing problem
return -EFAULT;
}
done+=1;
}
}
// Update file position value
*f_pos=*f_pos+done;
// If less bytes than the requested number are returned, fread will
// retry. Make sure the next read (retry) returns 0 -- this will cause
// fread to give up (EOF).
if(done<count) p_device_data->eof=1;
return done; // Number of bytes read (total)
minor_null:
// Minor number 0 is reserved for communication with this driver.
// Reading from this minor number returns a list of the devices currently
// registered. This allows you to identify the minor number to use for a
// given device.
// Return 0 (end of file) if not reading from beginning (f_pos==0).
// This will keep fread from trying to read the full number of requested
// bytes. You must read the whole data with the initial call because
// subsequent calls will return "end of file".
if(*f_pos>0) return 0;
p=(char *)usbtmc_buffer;
t=0;
// Add header line to buffer
p=p+usbtmc_buffer_append(p,
"Minor Number\tManufacturer\tProduct\tSerial Number\n",&t);
// Find out which minor numbers are used
for(n=1;n<USBTMC_MINOR_NUMBERS;n++)
if(usbtmc_minors[n]) {
// Add entry for this device
p_device=interface_to_usbdev(usbtmc_devs[n]->intf);
sprintf(p,"%03d\t",n); p=p+4; t=t+4;
s=p_device->manufacturer;
p=p+usbtmc_buffer_append(p,s,&t);
p=p+usbtmc_buffer_append(p,"\t",&t);
s=p_device->product;
p=p+usbtmc_buffer_append(p,s,&t);
p=p+usbtmc_buffer_append(p,"\t",&t);
s=p_device->serial;
p=p+usbtmc_buffer_append(p,s,&t);
p=p+usbtmc_buffer_append(p,"\n",&t);
}
// Copy buffer to user space
if(copy_to_user(buf,usbtmc_buffer,t)) {
// There must have been an addressing problem
return -EFAULT;
}
// Update file position value
*f_pos=*f_pos+t;
return t; // Number of bytes read
}
// This function sends a command to an instrument by wrapping it into a
// USMTMC DEV_DEP_MSG_OUT message.
ssize_t usbtmc_write(struct file *filp,
const char __user *buf,
size_t count,
loff_t *f_pos)
{
struct usbtmc_device_data *p_device_data;
unsigned int pipe;
int retval;
int actual;
unsigned long int n_bytes;
int n;
int remaining;
int done;
int this_part;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_write called\n");
#endif
// Get pointer to private data structure
p_device_data=filp->private_data;
if(!p_device_data->devno) goto minor_null; // Driver communication
p_device_data->eof=0;
remaining=count;
done=0;
while(remaining>0) // Still bytes to send
{
if(remaining>USBTMC_SIZE_IOBUFFER-12) {
// Use maximum size (limited by driver internal buffer size)
this_part=USBTMC_SIZE_IOBUFFER-12; // Use maximum size
usbtmc_buffer[8]=0; // This is not the last transfer -- see below
}
else {
// Can send remaining bytes in a single transaction
this_part=remaining;
usbtmc_buffer[8]=1; // Message ends with this transfer -- see below
}
// Setup IO buffer for DEV_DEP_MSG_OUT message
usbtmc_buffer[0]=1; // DEV_DEP_MSG_OUT
usbtmc_buffer[1]=p_device_data->bTag; // Transfer ID (bTag)
usbtmc_buffer[2]=~(p_device_data->bTag); // Inverse of bTag
usbtmc_buffer[3]=0; // Reserved
usbtmc_buffer[4]=this_part&255; // Transfer size (first byte)
usbtmc_buffer[5]=(this_part>>8)&255; // Transfer size (second byte)
usbtmc_buffer[6]=(this_part>>16)&255; // Transfer size (third byte)
usbtmc_buffer[7]=(this_part>>24)&255; // Transfer size (fourth byte)
// usbtmc_buffer[8] is set above...
usbtmc_buffer[9]=0; // Reserved
usbtmc_buffer[10]=0; // Reserved
usbtmc_buffer[11]=0; // Reserved
// Append write buffer (instrument command) to USBTMC message
if(copy_from_user(&(usbtmc_buffer[12]),buf+done,this_part)) {
// There must have been an addressing problem
return -EFAULT;
}
if(this_part==remaining) { // If this is the last transfer...
if(p_device_data->rem_nl_on_write==USBTMC_ATTRIB_VAL_ON) {
// See if last byte to send is a '\n'...
if(usbtmc_buffer[12+this_part-1]=='\n') {
// Remove it!
this_part--;
}
}
}
// Add zero bytes to achieve 4-byte alignment
n_bytes=12+this_part;
if(this_part%4) {
n_bytes+=4-this_part%4;
for(n=12+this_part;n<n_bytes;n++) usbtmc_buffer[n]=0;
}
// Create pipe for bulk out transfer
pipe=usb_sndbulkpipe(p_device_data->usb_dev,p_device_data->bulk_out);
// Send bulk URB
retval=usb_bulk_msg(p_device_data->usb_dev,pipe,usbtmc_buffer,n_bytes,
&actual,p_device_data->timeout);
// Store bTag (in case we need to abort)
usbtmc_last_write_bTag=p_device_data->bTag;
// Increment bTag -- and increment again if zero
(p_device_data->bTag)++;
if(!(p_device_data->bTag)) (p_device_data->bTag)++;
if(retval<0) {
printk(KERN_NOTICE "USBTMC: Unable to send data, error %d\n",
retval);
if(p_device_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(0,filp,USBTMC_IOCTL_ABORT_BULK_OUT,
0);
return retval;
}
remaining-=this_part;
done+=this_part;
}
return count;
minor_null:
// Minor number 0 is reserved for communication with driver
return -EPERM;
}
int usbtmc_ioctl_abort_bulk_in (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Abort the last bulk in transfer and restore synchronization.
// See section 4.2.1.4 of the USBTMC specifcation for details.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
int n;
int actual;
struct usb_host_interface *current_setting;
int max_size;
// Get pointer to private data structure
p_device_data=filp->private_data;
// INITIATE_ABORT_BULK_IN request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, // INITIATE_ABORT
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_ENDPOINT, // Request type
usbtmc_last_read_bTag, // Last transaction's bTag value
p_device_data->bulk_in, // Endpoint
usbtmc_buffer, // Target buffer
2, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: INITIATE_ABORT_BULK_IN returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]==USBTMC_STATUS_FAILED) {
// No transfer in progress and bulk in fifo is empty.
return 0;
}
if(usbtmc_buffer[0]!=USBTMC_STATUS_SUCCESS)
{
printk(KERN_NOTICE
"USBTMC: INITIATE_ABORT_BULK_IN returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
// Get wMaxPacketSize
max_size=0;
current_setting=p_device_data->intf->cur_altsetting;
// Find data structure for bulk in endpoint
for(n=0;n<current_setting->desc.bNumEndpoints;n++)
if(current_setting->endpoint[n].desc.bEndpointAddress==
p_device_data->bulk_in)
// Now get that endpoint's wMaxPacketSize
max_size=current_setting->endpoint[n].desc.wMaxPacketSize;
if(max_size==0) {
printk(KERN_NOTICE "USBTMC: Couldn't get wMaxPacketSize\n");
return -EPERM;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: wMaxPacketSize is %d\n",max_size);
#endif
n=0; // To keep track of the number of read operations (see below)
do {
// Read a chunk of data from bulk in endpoint
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Reading from bulk in EP\n");
#endif
// Read from bulk in EP
rv=usb_bulk_msg(p_device_data->usb_dev,
usb_rcvbulkpipe(p_device_data->usb_dev,
p_device_data->bulk_in), // Bulk in pipe
usbtmc_buffer, // Target buffer
USBTMC_SIZE_IOBUFFER, // Max characters to read
&actual, // Actual characters read
p_device_data->timeout); // Timeout (jiffies)
n++;
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_bulk_msg returned %d\n",
rv);
return rv;
}
} while ((actual==max_size)&&(n<USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
if(actual==max_size) { // Couldn't clear device buffer
printk(KERN_NOTICE
"USBTMC: Couldn't clear device buffer within %d cycles\n",
USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
return -EPERM;
}
n=0; // To keep track of the number of read operations (see below)
usbtmc_abort_bulk_in_status:
// CHECK_ABORT_BULK_IN_STATUS request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, // CHECK_STATUS
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_ENDPOINT, // Request type
0, // Reserved
p_device_data->bulk_in, // Endpoint
usbtmc_buffer, // Target buffer
0x08, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: INITIATE_ABORT_BULK_IN returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]==USBTMC_STATUS_SUCCESS)
return 0;
if(usbtmc_buffer[0]!=USBTMC_STATUS_PENDING) {
printk(KERN_NOTICE
"USBTMC: INITIATE_ABORT_BULK_IN returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
// Is there data to read off the device?
if(usbtmc_buffer[1]==1) do {
// Read a chunk of data from bulk in endpoint
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Reading from bulk in EP\n");
#endif
// Read from bulk in EP
rv=usb_bulk_msg(p_device_data->usb_dev,
usb_rcvbulkpipe(p_device_data->usb_dev,
p_device_data->bulk_in), // Bulk in pipe
usbtmc_buffer, // Target buffer
USBTMC_SIZE_IOBUFFER, // Max characters to read
&actual, // Actual characters read
p_device_data->timeout); // Timeout (jiffies)
n++;
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_bulk_msg returned %d\n",
rv);
return rv;
}
} while ((actual=max_size)&&(n<USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
if(actual==max_size) { // Couldn't clear device buffer
printk(KERN_NOTICE
"USBTMC: Couldn't clear device buffer within %d cycles\n",
USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
return -EPERM;
}
// Device should be clear at this point. Now check status again!
goto usbtmc_abort_bulk_in_status;
}
int usbtmc_ioctl_abort_bulk_out (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Abort the last bulk out transfer and restore synchronization.
// See section 4.2.1.2 of the USBTMC specifcation for details.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
int n;
// Get pointer to private data structure
p_device_data=filp->private_data;
// INITIATE_ABORT_BULK_OUT request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, // INITIATE_ABORT
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_ENDPOINT, // Request type
usbtmc_last_write_bTag, // Last transaction's bTag value
p_device_data->bulk_out, // Endpoint
usbtmc_buffer, // Target buffer
2, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: INITIATE_ABORT_BULK_OUT returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]!=USBTMC_STATUS_SUCCESS)
{
printk(KERN_NOTICE
"USBTMC: INITIATE_ABORT_BULK_OUT returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
n=0; // To keep track of the number of turns (see below)
usbtmc_abort_bulk_out_check_status:
// CHECK_ABORT_BULK_OUT request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, // CHECK_STATUS
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_ENDPOINT, // Request type
0, // Reserved
p_device_data->bulk_out, // Endpoint
usbtmc_buffer, // Target buffer
0x08, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
n++;
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: CHECK_ABORT_BULK_OUT returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]==USBTMC_STATUS_SUCCESS)
goto usbtmc_abort_bulk_out_clear_halt;
if((usbtmc_buffer[0]==USBTMC_STATUS_PENDING)&&
(n<USBTMC_MAX_READS_TO_CLEAR_BULK_IN))
goto usbtmc_abort_bulk_out_check_status;
printk(KERN_NOTICE "USBTMC: CHECK_ABORT_BULK_OUT returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
usbtmc_abort_bulk_out_clear_halt:
// CLEAR_FEATURE request to clear bulk out halt
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_sndctrlpipe(p_device_data->usb_dev,0), // Control out pipe
USB_REQ_CLEAR_FEATURE, // Clear feature request
USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT, // To EP
USB_ENDPOINT_HALT, // Feature ENDPOINT_HALT
p_device_data->bulk_out,
usbtmc_buffer, // Target buffer
0, // Although we don't really want data this time
p_device_data->timeout);
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
return 0;
}
int usbtmc_ioctl_clear (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Clear the device's input and output buffers.
// See section 4.2.1.6 of the USBTMC specification for details.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
int n;
int actual;
struct usb_host_interface *current_setting;
int max_size;
// Get pointer to private data structure
p_device_data=filp->private_data;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Sending INITIATE_CLEAR request\n");
#endif
// INITIATE_CLEAR request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_INITIATE_CLEAR, // INITIATE_CLEAR
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE, // Request type
0, // Interface number (always zero for USBTMC)
0, // Reserved
usbtmc_buffer, // Target buffer
1, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: INITIATE_CLEAR returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]!=USBTMC_STATUS_SUCCESS) {
printk(KERN_NOTICE "USBTMC: INITIATE_CLEAR returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
// Get wMaxPacketSize
max_size=0;
current_setting=p_device_data->intf->cur_altsetting;
// Find data structure for bulk in endpoint
for(n=0;n<current_setting->desc.bNumEndpoints;n++)
if(current_setting->endpoint[n].desc.bEndpointAddress==
p_device_data->bulk_in)
// Now get that endpoint's wMaxPacketSize
max_size=current_setting->endpoint[n].desc.wMaxPacketSize;
if(max_size==0) {
printk(KERN_NOTICE "USBTMC: Couldn't get wMaxPacketSize\n");
return -EPERM;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: wMaxPacketSize is %d\n",max_size);
#endif
n=0; // To keep track of the number of read operations (see below)
usbtmc_clear_check_status:
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Sending CHECK_CLEAR_STATUS request\n");
#endif
// CHECK_CLEAR_STATUS request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_CHECK_CLEAR_STATUS, // INITIATE_CLEAR
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE, // Request type
0, // Interface number (always zero for USBTMC)
0, // Reserved
usbtmc_buffer, // Target buffer
2, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: CHECK_CLEAR_STATUS returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]==USBTMC_STATUS_SUCCESS) {
// Done. No data to read off the device.
goto usbtmc_clear_bulk_out_halt;
}
if(usbtmc_buffer[0]!=USBTMC_STATUS_PENDING) {
printk(KERN_NOTICE "USBTMC: CHECK_CLEAR_STATUS returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
// Check bmClear field to see if data needs to be read off
// the device.
if(usbtmc_buffer[1]==1) do {
// Read a chunk of data from bulk in endpoint
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Reading from bulk in EP\n");
#endif
// Read from bulk in EP
rv=usb_bulk_msg(p_device_data->usb_dev,
usb_rcvbulkpipe(p_device_data->usb_dev,
p_device_data->bulk_in), // Bulk in pipe
usbtmc_buffer, // Target buffer
USBTMC_SIZE_IOBUFFER, // Max characters to read
&actual, // Actual characters read
p_device_data->timeout); // Timeout (jiffies)
n++;
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",
rv);
return rv;
}
} while ((actual==max_size)&&(n<USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
if(actual==max_size) { // Couldn't clear device buffer
printk(KERN_NOTICE
"USBTMC: Couldn't clear device buffer within %d cycles\n",
USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
return -EPERM;
}
// Device should be clear at this point. Now check status again!
goto usbtmc_clear_check_status;
usbtmc_clear_bulk_out_halt:
// Finally, clear bulk out halt
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_sndctrlpipe(p_device_data->usb_dev,0), // Control out pipe
USB_REQ_CLEAR_FEATURE, // Clear feature request
USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT, // To EP
USB_ENDPOINT_HALT, // Feature ENDPOINT_HALT
p_device_data->bulk_out,
usbtmc_buffer, // Target buffer
0, // Although we don't really want data this time
p_device_data->timeout);
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
return 0;
}
int usbtmc_ioctl_set_attribute (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Set driver attribute.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
// Get pointer to private data structure
p_device_data=filp->private_data;
switch(((struct usbtmc_attribute *)arg)->attribute)
{
case USBTMC_ATTRIB_AUTO_ABORT_ON_ERROR:
if((((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_ON)&&
(((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_OFF))
return -EINVAL;
p_device_data->auto_abort=((struct usbtmc_attribute *)arg)->value;
break;
case USBTMC_ATTRIB_READ_MODE:
if((((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_FREAD)&&
(((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_READ))
return -EINVAL;
p_device_data->fread=((struct usbtmc_attribute *)arg)->value;
break;
case USBTMC_ATTRIB_TIMEOUT:
if(((struct usbtmc_attribute *)arg)->value<0)
return -EINVAL;
p_device_data->timeout=
((struct usbtmc_attribute *)arg)->value/1000*HZ;
break;
case USBTMC_ATTRIB_TERM_CHAR_ENABLED:
if((((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_ON)&&
(((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_OFF))
return -EINVAL;
p_device_data->term_char_enabled=
((struct usbtmc_attribute *)arg)->value;
break;
case USBTMC_ATTRIB_TERM_CHAR:
if((((struct usbtmc_attribute *)arg)->value<0)||
(((struct usbtmc_attribute *)arg)->value>255))
return -EINVAL;
p_device_data->term_char=
((struct usbtmc_attribute *)arg)->value;
break;
case USBTMC_ATTRIB_ADD_NL_ON_READ:
if((((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_ON)&&
(((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_OFF))
return -EINVAL;
p_device_data->add_nl_on_read=
((struct usbtmc_attribute *)arg)->value;
break;
case USBTMC_ATTRIB_REM_NL_ON_WRITE:
if((((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_ON)&&
(((struct usbtmc_attribute *)arg)->value!=
USBTMC_ATTRIB_VAL_OFF))
return -EINVAL;
p_device_data->rem_nl_on_write=
((struct usbtmc_attribute *)arg)->value;
break;
default:
// Bad attribute or read-only
return -EINVAL;
}
return 0;
}
int usbtmc_ioctl_get_attribute (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Read driver attribute.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int n;
int count;
// Get pointer to private data structure
p_device_data=filp->private_data;
switch(((struct usbtmc_attribute *)arg)->attribute)
{
case USBTMC_ATTRIB_AUTO_ABORT_ON_ERROR:
((struct usbtmc_attribute *)arg)->value=p_device_data->auto_abort;
break;
case USBTMC_ATTRIB_READ_MODE:
((struct usbtmc_attribute *)arg)->value=p_device_data->fread;
break;
case USBTMC_ATTRIB_TIMEOUT:
((struct usbtmc_attribute *)arg)->value=
p_device_data->timeout/HZ*1000;
break;
case USBTMC_ATTRIB_NUM_INSTRUMENTS:
count=0;
for(n=1;n<USBTMC_MINOR_NUMBERS;n++)
if(usbtmc_minors[n]) count++;
((struct usbtmc_attribute *)arg)->value=count;
break;
case USBTMC_ATTRIB_MINOR_NUMBERS:
((struct usbtmc_attribute *)arg)->value=
USBTMC_MINOR_NUMBERS; // defined in usbtmc.h
break;
case USBTMC_ATTRIB_SIZE_IO_BUFFER:
((struct usbtmc_attribute *)arg)->value=
USBTMC_SIZE_IOBUFFER; // defined in usbtmc.h
break;
case USBTMC_ATTRIB_DEFAULT_TIMEOUT:
((struct usbtmc_attribute *)arg)->value=
USBTMC_DEFAULT_TIMEOUT/HZ*1000;
// defined in usbtmc.h (in jiffies)
break;
case USBTMC_ATTRIB_DEBUG_MODE:
((struct usbtmc_attribute *)arg)->value=0;
#ifdef USBTMC_DEBUG
((struct usbtmc_attribute *)arg)->value=1;
#endif
// defined at the beginning of this file
break;
case USBTMC_ATTRIB_VERSION:
((struct usbtmc_attribute *)arg)->value=USBTMC_VERSION;
// defined at the beginning of this file
break;
case USBTMC_ATTRIB_TERM_CHAR_ENABLED:
((struct usbtmc_attribute *)arg)->value=
p_device_data->term_char_enabled;
break;
case USBTMC_ATTRIB_TERM_CHAR:
((struct usbtmc_attribute *)arg)->value=
p_device_data->term_char;
break;
case USBTMC_ATTRIB_ADD_NL_ON_READ:
((struct usbtmc_attribute *)arg)->value=
p_device_data->add_nl_on_read;
break;
case USBTMC_ATTRIB_REM_NL_ON_WRITE:
((struct usbtmc_attribute *)arg)->value=
p_device_data->rem_nl_on_write;
break;
default:
return -EINVAL;
}
return 0;
}
int usbtmc_ioctl_clear_out_halt (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Send CLEAR_FEATURE request to clear bulk out endpoint halt.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
// Get pointer to private data structure
p_device_data=filp->private_data;
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_sndctrlpipe(p_device_data->usb_dev,0), // Control out pipe
USB_REQ_CLEAR_FEATURE, // Clear feature request
USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT, // To EP
USB_ENDPOINT_HALT, // Feature ENDPOINT_HALT
p_device_data->bulk_out,
usbtmc_buffer, // Target buffer
0, // Although we don't really want data this time
p_device_data->timeout);
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
return 0;
}
int usbtmc_ioctl_clear_in_halt (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Send CLEAR_FEATURE request to clear bulk in endpoint halt.
// Normally, you should not need this function. If a read transaction is
// not processed properly (e.g. if a timeout occurs), ABORT_BULK_IN is usually
// a better choice.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
// Get pointer to private data structure
p_device_data=filp->private_data;
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_sndctrlpipe(p_device_data->usb_dev,0), // Control out pipe
USB_REQ_CLEAR_FEATURE, // Clear feature request
USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT, // To EP
USB_ENDPOINT_HALT, // Feature ENDPOINT_HALT
p_device_data->bulk_in,
usbtmc_buffer, // Target buffer
0, // Although we don't really want data this time
p_device_data->timeout);
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
return 0;
}
int usbtmc_ioctl_get_capabilities (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Returns information about the device's optional capabilities.
// See section 4.2.1.8 of the USBTMC specifcation for details.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
// Get pointer to private data structure
p_device_data=filp->private_data;
// GET_CAPABILITIES request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_GET_CAPABILITIES, // GET_CAPABILITIES
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE, // Request type
0, // Interface number (always zero for USBTMC)
0, // Reserved
usbtmc_buffer, // Target buffer
0x18, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: GET_CAPABILITIES returned %x\n",
usbtmc_buffer[0]);
printk(KERN_NOTICE "USBTMC: Interface capabilities are %x\n",
usbtmc_buffer[4]);
printk(KERN_NOTICE "USBTMC: Device capabilities are %x\n",
usbtmc_buffer[5]);
printk(KERN_NOTICE "USBTMC: USB488 interface capabilities are %x\n",
usbtmc_buffer[14]);
printk(KERN_NOTICE "USBTMC: USB488 device capabilities are %x\n",
usbtmc_buffer[15]);
#endif
if(usbtmc_buffer[0]!=USBTMC_STATUS_SUCCESS) {
printk(KERN_NOTICE "USBTMC: GET_CAPABILITIES returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
((struct usbtmc_dev_capabilities*)arg)->interface_capabilities=
usbtmc_buffer[4];
((struct usbtmc_dev_capabilities*)arg)->device_capabilities=
usbtmc_buffer[5];
((struct usbtmc_dev_capabilities*)arg)->usb488_interface_capabilities=
usbtmc_buffer[14];
((struct usbtmc_dev_capabilities*)arg)->usb488_device_capabilities=
usbtmc_buffer[15];
return 0;
}
int usbtmc_ioctl_indicator_pulse (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Turns on the device's activity indicator for identification.
// This capability is optional. When in doubt, use GET_CAPABILITIES to check
// for support.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
// Get pointer to private data structure
p_device_data=filp->private_data;
// INDICATOR_PULSE request
rv=usb_control_msg(
p_device_data->usb_dev, // USB device structure
usb_rcvctrlpipe(p_device_data->usb_dev,0), // Control in pipe
USBTMC_REQUEST_INDICATOR_PULSE, // INDICATOR_PULSE
USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE, // Request type
0, // Interface number (always zero for USBTMC)
0, // Reserved
usbtmc_buffer, // Target buffer
0x01, // Number of characters to read
p_device_data->timeout); // Timeout (jiffies)
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_control_msg returned %d\n",rv);
return rv;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: INDICATOR_PULSE returned %x\n",
usbtmc_buffer[0]);
#endif
if(usbtmc_buffer[0]!=USBTMC_STATUS_SUCCESS)
{
printk(KERN_NOTICE "USBTMC: INDICATOR_PULSE returned %x\n",
usbtmc_buffer[0]);
return -EPERM;
}
return 0;
}
int usbtmc_ioctl_instrument_data (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Fills usbtmc_instrument data structure.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
struct usb_device *p_device;
int n;
// Get pointer to private data structure
p_device_data=filp->private_data;
// See if minor number is OK
if(!usbtmc_minors[((struct usbtmc_instrument *)arg)->minor_number])
// This minor number is not in use!
return -EINVAL;
// Now fill the data structure
p_device=interface_to_usbdev(
usbtmc_devs[((struct usbtmc_instrument *)arg)->minor_number]->intf);
// Manufacturer
n=strlen(p_device->manufacturer);
if(n>199) n=199;
if(copy_to_user(((struct usbtmc_instrument *)arg)->manufacturer,
p_device->manufacturer,n)) {
// There must have been an addressing problem
return -EFAULT;
}
((struct usbtmc_instrument *)arg)->manufacturer[n]=0;
// Product
n=strlen(p_device->product);
if(n>199) n=199;
if(copy_to_user(((struct usbtmc_instrument *)arg)->product,
p_device->product,n)) {
// There must have been an addressing problem
return -EFAULT;
}
((struct usbtmc_instrument *)arg)->product[n]=0;
// Serial number
n=strlen(p_device->product);
if(n>199) n=199;
if(copy_to_user(((struct usbtmc_instrument *)arg)->serial_number,
p_device->serial,n)) {
// There must have been an addressing problem
return -EFAULT;
}
((struct usbtmc_instrument *)arg)->serial_number[n]=0;
return 0;
}
int usbtmc_ioctl_reset_conf (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// Reinitialize current USB configuration and its interfaces.
// Called by usbtmc_ioctl... See below!
{
struct usbtmc_device_data *p_device_data;
int rv;
// Get pointer to private data structure
p_device_data=filp->private_data;
// Reset configuration
rv=usb_reset_configuration(p_device_data->usb_dev);
if(rv<0) { // I/O error
printk(KERN_NOTICE "USBTMC: usb_reset_configuration returned %d\n",rv);
return rv;
}
return 0;
}
int usbtmc_ioctl (struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
// ioctl is used for special operations (other than message-based I/O), such
// as device clear.
{
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Ioctl function called\n");
#endif
switch(cmd)
{
case USBTMC_IOCTL_SET_ATTRIBUTE:
return usbtmc_ioctl_set_attribute(inode,filp,cmd,arg);
case USBTMC_IOCTL_GET_ATTRIBUTE:
return usbtmc_ioctl_get_attribute(inode,filp,cmd,arg);
case USBTMC_IOCTL_CLEAR_OUT_HALT:
return usbtmc_ioctl_clear_out_halt(inode,filp,cmd,arg);
case USBTMC_IOCTL_CLEAR_IN_HALT:
return usbtmc_ioctl_clear_in_halt(inode,filp,cmd,arg);
case USBTMC_IOCTL_GET_CAPABILITIES:
return usbtmc_ioctl_get_capabilities(inode,filp,cmd,arg);
case USBTMC_IOCTL_INDICATOR_PULSE:
return usbtmc_ioctl_indicator_pulse(inode,filp,cmd,arg);
case USBTMC_IOCTL_CLEAR:
return usbtmc_ioctl_clear(inode,filp,cmd,arg);
case USBTMC_IOCTL_ABORT_BULK_OUT:
return usbtmc_ioctl_abort_bulk_out(inode,filp,cmd,arg);
case USBTMC_IOCTL_ABORT_BULK_IN:
return usbtmc_ioctl_abort_bulk_in(inode,filp,cmd,arg);
case USBTMC_IOCTL_INSTRUMENT_DATA:
return usbtmc_ioctl_instrument_data(inode,filp,cmd,arg);
case USBTMC_IOCTL_RESET_CONF:
return usbtmc_ioctl_reset_conf(inode,filp,cmd,arg);
default:
return -EBADRQC; // Invalid request code
}
}
loff_t usbtmc_llseek(struct file *filp,loff_t position,int x)
// Seek (random access) doesn't make sense with test instruments, so this
// function returns an error.
{
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_llseek called\n");
#endif
return -EPERM; // Operation not permitted
}
// This structure is used to publish the char device driver entry points
static struct file_operations fops = {
.owner=THIS_MODULE,
.read=usbtmc_read,
.write=usbtmc_write,
.open=usbtmc_open,
.release=usbtmc_release,
.unlocked_ioctl=usbtmc_ioctl,
.llseek=usbtmc_llseek,
};
static int usbtmc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
// The probe function is called whenever a device is connected which is serviced
// by this driver (USBTMC device).
{
int retcode;
struct usbtmc_device_data *p_device_data;
struct usb_device *p_device;
int n;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_probe called\n");
#endif
// Wait for completion of driver initialization
// wait_for_completion(&usbtmc_init_done);
// Allocate memory for device specific data
if(!(p_device_data=kmalloc(sizeof(struct usbtmc_device_data),GFP_KERNEL))) {
printk(KERN_ALERT "USBTMC: Unable to allocate kernel memory\n");
goto exit_kmalloc;
}
// Find the first free minor number
n=1;
while(n<USBTMC_MINOR_NUMBERS && usbtmc_minors[n]!=0) n++;
if(n==USBTMC_MINOR_NUMBERS) {
printk(KERN_ALERT "USBTMC: No free minor number found\n");
retcode=-ENOMEM;
goto exit_cdev_add;
}
// Now in use
usbtmc_minors[n]=1;
usbtmc_devs[n]=p_device_data;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Using minor number %d\n",n);
#endif
// Initialize cdev structure for this character device
// Set cdev structure to zero before calling cdev_init
memset(&p_device_data->cdev,0,sizeof(struct cdev));
cdev_init(&p_device_data->cdev,&fops);
p_device_data->cdev.owner=THIS_MODULE;
p_device_data->cdev.ops=&fops;
// Identify this instrument
p_device=interface_to_usbdev(intf);
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: New device attached:\n");
printk(KERN_NOTICE "USBTMC: Product: %s\n",p_device->product);
printk(KERN_NOTICE "USBTMC: Manufacturer: %s\n",p_device->manufacturer);
printk(KERN_NOTICE "USBTMC: Serial number: %s\n",p_device->serial);
#endif
// Combine major and minor numbers
printk(KERN_NOTICE "USBTMC: MKDEV\n");
p_device_data->devno=MKDEV(MAJOR(dev),n);
// Add character device to kernel list
printk(KERN_NOTICE "USBTMC: CDEV_ADD\n");
if((retcode=cdev_add(&p_device_data->cdev,p_device_data->devno,1))) {
printk(KERN_ALERT "USBTMC: Unable to add character device\n");
goto exit_cdev_add;
}
// Store info about USB interface in private data structure
p_device_data->intf=intf;
p_device_data->id=id;
// Store pointer to usb device
p_device_data->usb_dev=usb_get_dev(interface_to_usbdev(intf));
// Associate pointer to private data with this interface
usb_set_intfdata(intf,p_device_data);
// Initialize USBTMC bTag and other fields
p_device_data->bTag=1;
p_device_data->eof=0;
p_device_data->fread=1;
p_device_data->timeout=USBTMC_DEFAULT_TIMEOUT;
p_device_data->term_char_enabled=0;
p_device_data->term_char='\n';
p_device_data->add_nl_on_read=0;
p_device_data->rem_nl_on_write=0;
return 0;
exit_cdev_add:
// Free memory for device specific data
kfree(p_device_data);
return retcode;
exit_kmalloc:
return -ENOMEM;
}
static void usbtmc_disconnect(struct usb_interface *intf)
// The disconnect function is called whenever a device serviced by the driver is
// disconnected.
{
struct usbtmc_device_data *p_device_data;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_disconnect called\n");
#endif
// Get pointer to private data
p_device_data=usb_get_intfdata(intf);
// Update array for minor number usage
usbtmc_minors[MINOR(p_device_data->devno)]=0;
// Remove character device from kernel list
cdev_del(&p_device_data->cdev);
// Decrease use count
usb_get_dev(p_device_data->usb_dev);
// Free memory allocated for private data
kfree(p_device_data);
return;
}
// This structure is used to pass information about this USB driver to the
// USB core (via usb_register)
static struct usb_driver usbtmc_driver = {
//.owner=THIS_MODULE,
.name="USBTMC", // Driver name
.id_table=usbtmc_devices, // Devices serviced by the driver
.probe=usbtmc_probe, // Probe function (called when device is connected)
.disconnect=usbtmc_disconnect // Disconnect function
};
static int usbtmc_init(void)
// This function is called when the driver is inserted into the kernel. It
// initializes and registers the driver.
{
int retcode;
int n;
int devno;
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_init called\n");
#endif
// Reset usbtmc_minors array
for(n=0;n<USBTMC_MINOR_NUMBERS;n++) usbtmc_minors[n]=0;
// Dynamically allocate char driver major/minor numbers
if((retcode=alloc_chrdev_region(&dev, // First major/minor number to use
0, // First minor number
USBTMC_MINOR_NUMBERS, // Number of minor numbers to reserve
"USBTMCCHR" // Char device driver name
))) {
printk(KERN_ALERT "USBTMC: Unable to allocate major/minor numbers\n");
goto exit_alloc_chrdev_region;
}
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Major number is %d\n", MAJOR(dev));
#endif
// Allocate I/O buffer
if(!(usbtmc_buffer=kmalloc(USBTMC_SIZE_IOBUFFER,GFP_KERNEL))) {
printk(KERN_ALERT "USBTMC: Unable to allocate kernel memory\n");
retcode=-ENOMEM;
goto exit_kmalloc;
}
// Initialize cdev structure for driver communication character device
// Set cdev structure to zero before calling cdev_init
memset(&cdev,0,sizeof(struct cdev));
cdev_init(&cdev,&fops);
cdev.owner=THIS_MODULE;
cdev.ops=&fops;
devno=MKDEV(MAJOR(dev),0);
// Add character device to kernel list
if((retcode=cdev_add(&cdev,devno,1))) {
printk(KERN_ALERT "USBTMC: Unable to add character device\n");
retcode=-ENODEV;
goto exit_cdev_add;
}
// Initialize completion for driver initialization
// init_completion(&usbtmc_init_done);
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Registering USB driver\n");
#endif
// Register USB driver with USB core
retcode=usb_register(&usbtmc_driver);
// complete(&usbtmc_init_done);
if(retcode) {
printk(KERN_ALERT "USBTMC: Unable to register driver\n");
goto exit_usb_register;
}
return 0; // So far so good
exit_usb_register:
// Remove character device from kernel list
cdev_del(&cdev);
exit_cdev_add:
// Free driver buffers
kfree(usbtmc_buffer);
exit_kmalloc:
// Unregister char driver major/minor numbers
unregister_chrdev_region(dev,USBTMC_MINOR_NUMBERS);
exit_alloc_chrdev_region:
return retcode;
}
static void usbtmc_exit(void)
// The exit function is called before the driver is unloaded from the kernel.
// It is supposed to clean up and free any resources allocated by the driver.
{
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: usbtmc_exit called\n");
printk(KERN_NOTICE "USBTMC: Unregistering major/minor numbers\n");
#endif
// Unregister char driver major/minor numbers
unregister_chrdev_region(dev,USBTMC_MINOR_NUMBERS);
// Release IO buffer allocated in usbtmc_init
kfree(usbtmc_buffer);
#ifdef USBTMC_DEBUG
printk(KERN_NOTICE "USBTMC: Deregistering driver\n");
#endif
// Unregister USB driver with USB core
usb_deregister(&usbtmc_driver);
}
module_init(usbtmc_init); // Inititialization function
module_exit(usbtmc_exit); // Shutdown function
MODULE_LICENSE("GPL");
// Revision history
//
// 1.0 05.11.2007 Initial version.
// 1.0.1 07.11.2007 Set cdev struct to zero prior to calling cdev_init().
// 1.0.2 09.11.2007 Bug fixes related to control requests.
// 1.0.3 13.11.2007 Automatic ABORT on error capability.
// 1.0.4 21.11.2007 Updated ioctl functions.
// Added GET_ATTRIBUTE and SET_ATTRIBUTE functions.
// Added usbtmc_ioctl command line utility.
// 1.1 08.12.2007 Added several new attributes.
// Wrote HTML documentation.
// usbtmc.h
// This file is part of a Linux kernel module for USBTMC (USB Test and
// Measurement Class) devices
// Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
// See usbtmc.c source file for license details
#include <linux/ioctl.h> // For _IO macro
// Driver parameters that you might want to tune...
// Maximum number of USBTMC devices to be concurrently serviced by this module
#define USBTMC_MINOR_NUMBERS 16
// Size of driver internal IO buffer. Must be multiple of 4 and at least as
// large as wMaxPacketSize (which is usually 512 bytes).
#define USBTMC_SIZE_IOBUFFER 4096
// Default USB timeout (in jiffies)
#define USBTMC_DEFAULT_TIMEOUT 10*HZ
// Maximum number of read cycles to empty bulk in endpoint during CLEAR and
// ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
// packet is never read.
#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100
// Other definitions
// Request values for USBTMC driver's ioctl entry point
#define USBTMC_IOC_NR 91
#define USBTMC_IOCTL_GET_CAPABILITIES _IO(USBTMC_IOC_NR,0)
#define USBTMC_IOCTL_INDICATOR_PULSE _IO(USBTMC_IOC_NR,1)
#define USBTMC_IOCTL_CLEAR _IO(USBTMC_IOC_NR,2)
#define USBTMC_IOCTL_ABORT_BULK_OUT _IO(USBTMC_IOC_NR,3)
#define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR,4)
#define USBTMC_IOCTL_SET_ATTRIBUTE _IO(USBTMC_IOC_NR,5)
#define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR,6)
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR,7)
//#define USBTMC_IOCTL_TIMEOUT _IO(USBTMC_IOC_NR,8)
#define USBTMC_IOCTL_GET_ATTRIBUTE _IO(USBTMC_IOC_NR,9)
#define USBTMC_IOCTL_INSTRUMENT_DATA _IO(USBTMC_IOC_NR,10)
#define USBTMC_IOCTL_RESET_CONF _IO(USBTMC_IOC_NR,11)
// Request names for usbtmc_ioctl command line utility
#define USBTMC_IOCTL_NAME_GET_CAPABILITIES "getcaps"
#define USBTMC_IOCTL_NAME_INDICATOR_PULSE "indpulse"
#define USBTMC_IOCTL_NAME_CLEAR "clear"
#define USBTMC_IOCTL_NAME_ABORT_BULK_OUT "abortout"
#define USBTMC_IOCTL_NAME_ABORT_BULK_IN "abortin"
#define USBTMC_IOCTL_NAME_SET_ATTRIBUTE "setattr"
#define USBTMC_IOCTL_NAME_CLEAR_OUT_HALT "clearouthalt"
#define USBTMC_IOCTL_NAME_CLEAR_IN_HALT "clearinhalt"
#define USBTMC_IOCTL_NAME_GET_ATTRIBUTE "getattr"
#define USBTMC_IOCTL_NAME_RESET_CONF "reset"
// This structure is used with USBTMC_IOCTL_GET_CAPABILITIES.
// See section 4.2.1.8 of the USBTMC specification for details.
struct usbtmc_dev_capabilities {
char interface_capabilities;
char device_capabilities;
char usb488_interface_capabilities;
char usb488_device_capabilities;
};
// This structure is used with USBTMC_IOCTL_SET_ATTRIBUTE and
// USBTMC_IOCTL_GET_ATTRIBUTE.
struct usbtmc_attribute {
int attribute;
int value;
};
// Defines for attributes and their values
#define USBTMC_ATTRIB_AUTO_ABORT_ON_ERROR 0
#define USBTMC_ATTRIB_NAME_AUTO_ABORT_ON_ERROR "autoabort"
#define USBTMC_ATTRIB_READ_MODE 1
#define USBTMC_ATTRIB_NAME_READ_MODE "readmode"
#define USBTMC_ATTRIB_TIMEOUT 2
#define USBTMC_ATTRIB_NAME_TIMEOUT "timeout"
#define USBTMC_ATTRIB_NUM_INSTRUMENTS 3
#define USBTMC_ATTRIB_NAME_NUM_INSTRUMENTS "numinst"
#define USBTMC_ATTRIB_MINOR_NUMBERS 4
#define USBTMC_ATTRIB_NAME_MINOR_NUMBERS "numminor"
#define USBTMC_ATTRIB_SIZE_IO_BUFFER 5
#define USBTMC_ATTRIB_NAME_SIZE_IO_BUFFER "buffsize"
#define USBTMC_ATTRIB_DEFAULT_TIMEOUT 6
#define USBTMC_ATTRIB_NAME_DEFAULT_TIMEOUT "deftimeout"
#define USBTMC_ATTRIB_DEBUG_MODE 7
#define USBTMC_ATTRIB_NAME_DEBUG_MODE "debug"
#define USBTMC_ATTRIB_VERSION 8
#define USBTMC_ATTRIB_NAME_VERSION "version"
#define USBTMC_ATTRIB_TERM_CHAR_ENABLED 9
#define USBTMC_ATTRIB_NAME_TERM_CHAR_ENABLED "termcharenab"
#define USBTMC_ATTRIB_TERM_CHAR 10
#define USBTMC_ATTRIB_NAME_TERM_CHAR "termchar"
#define USBTMC_ATTRIB_ADD_NL_ON_READ 11
#define USBTMC_ATTRIB_NAME_ADD_NL_ON_READ "addnlread"
#define USBTMC_ATTRIB_REM_NL_ON_WRITE 12
#define USBTMC_ATTRIB_NAME_REM_NL_ON_WRITE "remnlwrite"
#define USBTMC_ATTRIB_VAL_OFF 0
#define USBTMC_ATTRIB_NAME_VAL_OFF "off"
#define USBTMC_ATTRIB_VAL_ON 1
#define USBTMC_ATTRIB_NAME_VAL_ON "on"
#define USBTMC_ATTRIB_VAL_FREAD 0
#define USBTMC_ATTRIB_NAME_VAL_FREAD "fread"
#define USBTMC_ATTRIB_VAL_READ 1
#define USBTMC_ATTRIB_NAME_VAL_READ "read"
// This structure is used with USBTMC_IOCTL_INSTRUMENT_DATA.
struct usbtmc_instrument {
int minor_number;
char manufacturer[200];
char product[200];
char serial_number[200];
};
// USBTMC status values
#define USBTMC_STATUS_SUCCESS 0x01
#define USBTMC_STATUS_PENDING 0x02
#define USBTMC_STATUS_FAILED 0x80
#define USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS 0x81
#define USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS 0x82
#define USBTMC_STATUS_SPLIT_IN_PROGRESS 0x83
// USBTMC requests values
#define USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT 1
#define USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS 2
#define USBTMC_REQUEST_INITIATE_ABORT_BULK_IN 3
#define USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS 4
#define USBTMC_REQUEST_INITIATE_CLEAR 5
#define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
#define USBTMC_REQUEST_GET_CAPABILITIES 7
#define USBTMC_REQUEST_INDICATOR_PULSE 64
// usbtmc_ioctl.c
// This file is part of a Linux kernel module for USBTMC (USB Test and
// Measurement Class) devices. It allows access to the driver's ioctl
// entry point.
// Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
// See revision history at the end of this file
//
// 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 program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available at
// http://www.gnu.org/copyleft/gpl.html.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include "usbtmc.h"
int minor_number=0;
char devfile[100];
int request=-1;
int myfile;
int rv;
struct usbtmc_dev_capabilities devcaps;
struct usbtmc_attribute attr;
int main(int argc,char *argv[])
{
if(argc<3) goto print_usage;
// Convert parameter #1 (minor number)
sscanf(argv[1],"%d",&minor_number);
if((minor_number<1)||(minor_number>USBTMC_MINOR_NUMBERS)) {
printf("Error: Bad minor number.\n");
goto print_usage;
}
sprintf(devfile,"/dev/usbtmc%d",minor_number);
// Convert parameter #2 (request name)
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_GET_CAPABILITIES))
request=USBTMC_IOCTL_GET_CAPABILITIES;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_INDICATOR_PULSE))
request=USBTMC_IOCTL_INDICATOR_PULSE;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_CLEAR))
request=USBTMC_IOCTL_CLEAR;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_ABORT_BULK_OUT))
request=USBTMC_IOCTL_ABORT_BULK_OUT;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_ABORT_BULK_IN))
request=USBTMC_IOCTL_ABORT_BULK_IN;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_SET_ATTRIBUTE))
request=USBTMC_IOCTL_SET_ATTRIBUTE;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_CLEAR_OUT_HALT))
request=USBTMC_IOCTL_CLEAR_OUT_HALT;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_CLEAR_IN_HALT))
request=USBTMC_IOCTL_CLEAR_IN_HALT;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_GET_ATTRIBUTE))
request=USBTMC_IOCTL_GET_ATTRIBUTE;
if(!strcmp(argv[2],USBTMC_IOCTL_NAME_RESET_CONF))
request=USBTMC_IOCTL_RESET_CONF;
// Open device file
myfile=open(devfile,O_RDWR);
if(myfile==-1) {
printf("Error: Can't open device file %s.\n",devfile);
exit(-1);
}
switch(request) {
case USBTMC_IOCTL_INDICATOR_PULSE:
case USBTMC_IOCTL_CLEAR:
case USBTMC_IOCTL_ABORT_BULK_OUT:
case USBTMC_IOCTL_ABORT_BULK_IN:
case USBTMC_IOCTL_CLEAR_OUT_HALT:
case USBTMC_IOCTL_CLEAR_IN_HALT:
case USBTMC_IOCTL_RESET_CONF:
rv=ioctl(myfile,request,0);
if(rv==-1) {
printf("Error: ioctl returned %d.\n",rv);
}
break;
case USBTMC_IOCTL_GET_CAPABILITIES:
rv=ioctl(myfile,request,&devcaps);
printf("Interface capabilities: %u\n",
devcaps.interface_capabilities);
printf("Device capabilities: %u\n",
devcaps.device_capabilities);
printf("USB488 interface capabilities: %u\n",
devcaps.usb488_interface_capabilities);
printf("USB488 device capabilities: %u\n",
devcaps.usb488_device_capabilities);
break;
case USBTMC_IOCTL_SET_ATTRIBUTE:
case USBTMC_IOCTL_GET_ATTRIBUTE:
// Convert parameter #3 (attribute name)
attr.attribute=-1;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_AUTO_ABORT_ON_ERROR))
attr.attribute=USBTMC_ATTRIB_AUTO_ABORT_ON_ERROR;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_READ_MODE))
attr.attribute=USBTMC_ATTRIB_READ_MODE;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_TIMEOUT))
attr.attribute=USBTMC_ATTRIB_TIMEOUT;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_NUM_INSTRUMENTS))
attr.attribute=USBTMC_ATTRIB_NUM_INSTRUMENTS;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_MINOR_NUMBERS))
attr.attribute=USBTMC_ATTRIB_MINOR_NUMBERS;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_SIZE_IO_BUFFER))
attr.attribute=USBTMC_ATTRIB_SIZE_IO_BUFFER;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_DEFAULT_TIMEOUT))
attr.attribute=USBTMC_ATTRIB_DEFAULT_TIMEOUT;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_DEBUG_MODE))
attr.attribute=USBTMC_ATTRIB_DEBUG_MODE;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_VERSION))
attr.attribute=USBTMC_ATTRIB_VERSION;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_TERM_CHAR_ENABLED))
attr.attribute=USBTMC_ATTRIB_TERM_CHAR_ENABLED;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_TERM_CHAR))
attr.attribute=USBTMC_ATTRIB_TERM_CHAR;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_ADD_NL_ON_READ))
attr.attribute=USBTMC_ATTRIB_ADD_NL_ON_READ;
if(!strcmp(argv[3],USBTMC_ATTRIB_NAME_REM_NL_ON_WRITE))
attr.attribute=USBTMC_ATTRIB_REM_NL_ON_WRITE;
if(attr.attribute==-1) {
printf("Error: Bad attribute name\n");
close(myfile);
goto print_usage;
}
if(request==USBTMC_IOCTL_SET_ATTRIBUTE) {
attr.value=-1;
if(!strcmp(argv[4],USBTMC_ATTRIB_NAME_VAL_OFF))
attr.value=USBTMC_ATTRIB_VAL_OFF;
if(!strcmp(argv[4],USBTMC_ATTRIB_NAME_VAL_ON))
attr.value=USBTMC_ATTRIB_VAL_ON;
if(!strcmp(argv[4],USBTMC_ATTRIB_NAME_VAL_FREAD))
attr.value=USBTMC_ATTRIB_VAL_FREAD;
if(!strcmp(argv[4],USBTMC_ATTRIB_NAME_VAL_READ))
attr.value=USBTMC_ATTRIB_VAL_READ;
if(attr.value==-1) sscanf(argv[4],"%d",&attr.value);
}
rv=ioctl(myfile,request,&attr);
if(request==USBTMC_IOCTL_GET_ATTRIBUTE) {
if((attr.attribute==USBTMC_ATTRIB_AUTO_ABORT_ON_ERROR)||
(attr.attribute==USBTMC_ATTRIB_DEBUG_MODE)||
(attr.attribute==USBTMC_ATTRIB_TERM_CHAR_ENABLED)||
(attr.attribute==USBTMC_ATTRIB_ADD_NL_ON_READ)||
(attr.attribute==USBTMC_ATTRIB_REM_NL_ON_WRITE))
if(attr.value==USBTMC_ATTRIB_VAL_OFF)
printf("Value: %s\n",USBTMC_ATTRIB_NAME_VAL_OFF);
else
printf("Value: %s\n",USBTMC_ATTRIB_NAME_VAL_ON);
if(attr.attribute==USBTMC_ATTRIB_READ_MODE)
if(attr.value==USBTMC_ATTRIB_VAL_FREAD)
printf("Value: %s\n",USBTMC_ATTRIB_NAME_VAL_FREAD);
else
printf("Value: %s\n",USBTMC_ATTRIB_NAME_VAL_READ);
if(attr.attribute==USBTMC_ATTRIB_TIMEOUT)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_NUM_INSTRUMENTS)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_MINOR_NUMBERS)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_SIZE_IO_BUFFER)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_DEFAULT_TIMEOUT)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_VERSION)
printf("Value: %d\n",attr.value);
if(attr.attribute==USBTMC_ATTRIB_TERM_CHAR)
printf("Value: %d\n",attr.value);
}
break;
default:
printf("Error: Bad request name.\n");
close(myfile);
goto print_usage;
}
// Close device file
close(myfile);
exit(0);
print_usage:
printf("Usage:\n");
printf("usbtmc_ioctl n request [ attribute [ value ] ]\n");
printf("where\n");
printf("m = minor number, e. g. 1 for /dev/usbtmc1\n");
printf("request = { clear , setattr , getattr , reset etc}\n");
printf("attribute = { autoabort , readmode , timeout etc }\n");
printf("See html documentation for details!\n");
printf("Example:\n");
printf("usbtmc_ioctl 1 clear\n");
printf("Clears input and output buffer of device /dev/usbtmc1\n");
exit(-1);
}
// Revision history
//
// 1.0 05.11.2007 Initial version.
// 1.0.1 07.11.2007 Set cdev struct to zero prior to calling cdev_init().
// 1.0.2 09.11.2007 Bug fixes related to control requests.
// 1.0.3 13.11.2007 Automatic ABORT on error in FREAD (shell) mode.
// 1.0.4 02.12.2007 Added a whole bunch of attributes.
// 1.1 08.12.2007 Clean-up.
#!/bin/bash
module="usbtmc"
# Remove module from kernel (just in case it is still running)
/sbin/rmmod $module 2> /dev/null
# Install module
#/sbin/insmod /home/user/pts_fmcfd/pts/usbdriver/$module.ko
/sbin/insmod /home/user/pts/usbdriver/$module.ko 2> /dev/null
# Find major number used
major=$(cat /proc/devices | grep USBTMCCHR | awk '{print $1}')
#echo Using major number $major
# Remove old device files
rm -f /dev/${module}[0-9]
# Ceate new device files
mknod /dev/${module}0 c $major 0
mknod /dev/${module}1 c $major 1
mknod /dev/${module}2 c $major 2
mknod /dev/${module}3 c $major 3
mknod /dev/${module}4 c $major 4
mknod /dev/${module}5 c $major 5
mknod /dev/${module}6 c $major 6
mknod /dev/${module}7 c $major 7
mknod /dev/${module}8 c $major 8
mknod /dev/${module}9 c $major 9
# Change access mode
chmod 666 /dev/${module}0
chmod 666 /dev/${module}1
chmod 666 /dev/${module}2
chmod 666 /dev/${module}3
chmod 666 /dev/${module}4
chmod 666 /dev/${module}5
chmod 666 /dev/${module}6
chmod 666 /dev/${module}7
chmod 666 /dev/${module}8
chmod 666 /dev/${module}9
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment