mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Move the gpib drivers out of staging and into the "real" part of the kernel. This entails: - Remove the gpib Kconfig menu and Makefile build rule from staging. - Remove gpib/uapi from the header file search path in subdir-ccflags of the gpib Makefile - move the gpib/uapi files to include/uapi/linux - Move the gpib tree out of staging to drivers. - Remove the word "Linux" from the gpib Kconfig file. - Add the gpib Kconfig menu and Makefile build rule to drivers Signed-off-by: Dave Penkler <dpenkler@gmail.com> Link: https://patch.msgid.link/20251117144021.23569-5-dpenkler@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2679 lines
78 KiB
C
2679 lines
78 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/***************************************************************************
|
|
* driver for National Instruments usb to gpib adapters
|
|
* copyright : (C) 2004 by Frank Mori Hess
|
|
***************************************************************************/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#define dev_fmt pr_fmt
|
|
#define DRV_NAME KBUILD_MODNAME
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include "ni_usb_gpib.h"
|
|
#include "gpibP.h"
|
|
#include "nec7210.h"
|
|
#include "tnt4882_registers.h"
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("GPIB driver for National Instruments USB devices");
|
|
|
|
#define MAX_NUM_NI_USB_INTERFACES 128
|
|
static struct usb_interface *ni_usb_driver_interfaces[MAX_NUM_NI_USB_INTERFACES];
|
|
|
|
static int ni_usb_parse_status_block(const u8 *buffer, struct ni_usb_status_block *status);
|
|
static int ni_usb_set_interrupt_monitor(struct gpib_board *board, unsigned int monitored_bits);
|
|
static void ni_usb_stop(struct ni_usb_priv *ni_priv);
|
|
|
|
static DEFINE_MUTEX(ni_usb_hotplug_lock);
|
|
|
|
// calculates a reasonable timeout in that can be passed to usb functions
|
|
static inline unsigned long ni_usb_timeout_msecs(unsigned int usec)
|
|
{
|
|
if (usec == 0)
|
|
return 0;
|
|
return 2000 + usec / 500;
|
|
};
|
|
|
|
// returns timeout code byte for use in ni-usb-b instructions
|
|
static unsigned short ni_usb_timeout_code(unsigned int usec)
|
|
{
|
|
if (usec == 0)
|
|
return 0xf0;
|
|
else if (usec <= 10)
|
|
return 0xf1;
|
|
else if (usec <= 30)
|
|
return 0xf2;
|
|
else if (usec <= 100)
|
|
return 0xf3;
|
|
else if (usec <= 300)
|
|
return 0xf4;
|
|
else if (usec <= 1000)
|
|
return 0xf5;
|
|
else if (usec <= 3000)
|
|
return 0xf6;
|
|
else if (usec <= 10000)
|
|
return 0xf7;
|
|
else if (usec <= 30000)
|
|
return 0xf8;
|
|
else if (usec <= 100000)
|
|
return 0xf9;
|
|
else if (usec <= 300000)
|
|
return 0xfa;
|
|
else if (usec <= 1000000)
|
|
return 0xfb;
|
|
else if (usec <= 3000000)
|
|
return 0xfc;
|
|
else if (usec <= 10000000)
|
|
return 0xfd;
|
|
else if (usec <= 30000000)
|
|
return 0xfe;
|
|
else if (usec <= 100000000)
|
|
return 0xff;
|
|
else if (usec <= 300000000)
|
|
return 0x01;
|
|
/*
|
|
* NI driver actually uses 0xff for timeout T1000s, which is a bug in their code.
|
|
* I've verified on a usb-b that a code of 0x2 is correct for a 1000 sec timeout
|
|
*/
|
|
else if (usec <= 1000000000)
|
|
return 0x02;
|
|
pr_err("bug? usec is greater than 1e9\n");
|
|
return 0xf0;
|
|
}
|
|
|
|
static void ni_usb_bulk_complete(struct urb *urb)
|
|
{
|
|
struct ni_usb_urb_ctx *context = urb->context;
|
|
|
|
complete(&context->complete);
|
|
}
|
|
|
|
static void ni_usb_timeout_handler(struct timer_list *t)
|
|
{
|
|
struct ni_usb_priv *ni_priv = timer_container_of(ni_priv, t,
|
|
bulk_timer);
|
|
struct ni_usb_urb_ctx *context = &ni_priv->context;
|
|
|
|
context->timed_out = 1;
|
|
complete(&context->complete);
|
|
};
|
|
|
|
// I'm using nonblocking loosely here, it only means -EAGAIN can be returned in certain cases
|
|
static int ni_usb_nonblocking_send_bulk_msg(struct ni_usb_priv *ni_priv, void *data,
|
|
int data_length, int *actual_data_length,
|
|
int timeout_msecs)
|
|
{
|
|
struct usb_device *usb_dev;
|
|
int retval;
|
|
unsigned int out_pipe;
|
|
struct ni_usb_urb_ctx *context = &ni_priv->context;
|
|
|
|
*actual_data_length = 0;
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
if (!ni_priv->bus_interface) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -ENODEV;
|
|
}
|
|
if (ni_priv->bulk_urb) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -EAGAIN;
|
|
}
|
|
ni_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (!ni_priv->bulk_urb) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_pipe = usb_sndbulkpipe(usb_dev, ni_priv->bulk_out_endpoint);
|
|
init_completion(&context->complete);
|
|
context->timed_out = 0;
|
|
usb_fill_bulk_urb(ni_priv->bulk_urb, usb_dev, out_pipe, data, data_length,
|
|
&ni_usb_bulk_complete, context);
|
|
|
|
if (timeout_msecs)
|
|
mod_timer(&ni_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs));
|
|
|
|
retval = usb_submit_urb(ni_priv->bulk_urb, GFP_KERNEL);
|
|
if (retval) {
|
|
timer_delete_sync(&ni_priv->bulk_timer);
|
|
usb_free_urb(ni_priv->bulk_urb);
|
|
ni_priv->bulk_urb = NULL;
|
|
dev_err(&usb_dev->dev, "failed to submit bulk out urb, retval=%i\n",
|
|
retval);
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return retval;
|
|
}
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
wait_for_completion(&context->complete); // wait for ni_usb_bulk_complete
|
|
if (context->timed_out) {
|
|
usb_kill_urb(ni_priv->bulk_urb);
|
|
dev_err(&usb_dev->dev, "killed urb due to timeout\n");
|
|
retval = -ETIMEDOUT;
|
|
} else {
|
|
retval = ni_priv->bulk_urb->status;
|
|
}
|
|
|
|
timer_delete_sync(&ni_priv->bulk_timer);
|
|
*actual_data_length = ni_priv->bulk_urb->actual_length;
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
usb_free_urb(ni_priv->bulk_urb);
|
|
ni_priv->bulk_urb = NULL;
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_send_bulk_msg(struct ni_usb_priv *ni_priv, void *data, int data_length,
|
|
int *actual_data_length, int timeout_msecs)
|
|
{
|
|
int retval;
|
|
int timeout_msecs_remaining = timeout_msecs;
|
|
|
|
retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, data, data_length, actual_data_length,
|
|
timeout_msecs_remaining);
|
|
while (retval == -EAGAIN && (timeout_msecs == 0 || timeout_msecs_remaining > 0)) {
|
|
usleep_range(1000, 1500);
|
|
retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, data, data_length,
|
|
actual_data_length,
|
|
timeout_msecs_remaining);
|
|
if (timeout_msecs != 0)
|
|
--timeout_msecs_remaining;
|
|
}
|
|
if (timeout_msecs != 0 && timeout_msecs_remaining <= 0)
|
|
return -ETIMEDOUT;
|
|
return retval;
|
|
}
|
|
|
|
// I'm using nonblocking loosely here, it only means -EAGAIN can be returned in certain cases
|
|
static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv,
|
|
void *data, int data_length,
|
|
int *actual_data_length, int timeout_msecs,
|
|
int interruptible)
|
|
{
|
|
struct usb_device *usb_dev;
|
|
int retval;
|
|
unsigned int in_pipe;
|
|
struct ni_usb_urb_ctx *context = &ni_priv->context;
|
|
|
|
*actual_data_length = 0;
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
if (!ni_priv->bus_interface) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -ENODEV;
|
|
}
|
|
if (ni_priv->bulk_urb) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -EAGAIN;
|
|
}
|
|
ni_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (!ni_priv->bulk_urb) {
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
in_pipe = usb_rcvbulkpipe(usb_dev, ni_priv->bulk_in_endpoint);
|
|
init_completion(&context->complete);
|
|
context->timed_out = 0;
|
|
usb_fill_bulk_urb(ni_priv->bulk_urb, usb_dev, in_pipe, data, data_length,
|
|
&ni_usb_bulk_complete, context);
|
|
|
|
if (timeout_msecs)
|
|
mod_timer(&ni_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs));
|
|
|
|
retval = usb_submit_urb(ni_priv->bulk_urb, GFP_KERNEL);
|
|
if (retval) {
|
|
timer_delete_sync(&ni_priv->bulk_timer);
|
|
usb_free_urb(ni_priv->bulk_urb);
|
|
ni_priv->bulk_urb = NULL;
|
|
dev_err(&usb_dev->dev, "failed to submit bulk in urb, retval=%i\n", retval);
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return retval;
|
|
}
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
if (interruptible) {
|
|
if (wait_for_completion_interruptible(&context->complete)) {
|
|
/*
|
|
* If we got interrupted by a signal while
|
|
* waiting for the usb gpib to respond, we
|
|
* should send a stop command so it will
|
|
* finish up with whatever it was doing and
|
|
* send its response now.
|
|
*/
|
|
ni_usb_stop(ni_priv);
|
|
retval = -ERESTARTSYS;
|
|
/*
|
|
* now do an uninterruptible wait, it shouldn't take long
|
|
* for the board to respond now.
|
|
*/
|
|
wait_for_completion(&context->complete);
|
|
}
|
|
} else {
|
|
wait_for_completion(&context->complete);
|
|
}
|
|
if (context->timed_out) {
|
|
usb_kill_urb(ni_priv->bulk_urb);
|
|
dev_err(&usb_dev->dev, "killed urb due to timeout\n");
|
|
retval = -ETIMEDOUT;
|
|
} else {
|
|
if (ni_priv->bulk_urb->status)
|
|
retval = ni_priv->bulk_urb->status;
|
|
}
|
|
timer_delete_sync(&ni_priv->bulk_timer);
|
|
*actual_data_length = ni_priv->bulk_urb->actual_length;
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
usb_free_urb(ni_priv->bulk_urb);
|
|
ni_priv->bulk_urb = NULL;
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_receive_bulk_msg(struct ni_usb_priv *ni_priv, void *data,
|
|
int data_length, int *actual_data_length, int timeout_msecs,
|
|
int interruptible)
|
|
{
|
|
int retval;
|
|
int timeout_msecs_remaining = timeout_msecs;
|
|
|
|
retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, data, data_length,
|
|
actual_data_length, timeout_msecs_remaining,
|
|
interruptible);
|
|
while (retval == -EAGAIN && (timeout_msecs == 0 || timeout_msecs_remaining > 0)) {
|
|
usleep_range(1000, 1500);
|
|
retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, data, data_length,
|
|
actual_data_length,
|
|
timeout_msecs_remaining,
|
|
interruptible);
|
|
if (timeout_msecs != 0)
|
|
--timeout_msecs_remaining;
|
|
}
|
|
if (timeout_msecs && timeout_msecs_remaining <= 0)
|
|
return -ETIMEDOUT;
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_receive_control_msg(struct ni_usb_priv *ni_priv, __u8 request,
|
|
__u8 requesttype, __u16 value, __u16 index,
|
|
void *data, __u16 size, int timeout_msecs)
|
|
{
|
|
struct usb_device *usb_dev;
|
|
int retval;
|
|
unsigned int in_pipe;
|
|
|
|
mutex_lock(&ni_priv->control_transfer_lock);
|
|
if (!ni_priv->bus_interface) {
|
|
mutex_unlock(&ni_priv->control_transfer_lock);
|
|
return -ENODEV;
|
|
}
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
in_pipe = usb_rcvctrlpipe(usb_dev, 0);
|
|
retval = usb_control_msg(usb_dev, in_pipe, request, requesttype, value, index, data,
|
|
size, timeout_msecs);
|
|
mutex_unlock(&ni_priv->control_transfer_lock);
|
|
return retval;
|
|
}
|
|
|
|
static void ni_usb_soft_update_status(struct gpib_board *board, unsigned int ni_usb_ibsta,
|
|
unsigned int clear_mask)
|
|
{
|
|
static const unsigned int ni_usb_ibsta_mask = SRQI | ATN | CIC | REM | LACS | TACS | LOK;
|
|
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
unsigned int need_monitoring_bits = ni_usb_ibsta_monitor_mask;
|
|
unsigned long flags;
|
|
|
|
board->status &= ~clear_mask;
|
|
board->status &= ~ni_usb_ibsta_mask;
|
|
board->status |= ni_usb_ibsta & ni_usb_ibsta_mask;
|
|
if (ni_usb_ibsta & DCAS)
|
|
push_gpib_event(board, EVENT_DEV_CLR);
|
|
if (ni_usb_ibsta & DTAS)
|
|
push_gpib_event(board, EVENT_DEV_TRG);
|
|
|
|
spin_lock_irqsave(&board->spinlock, flags);
|
|
/* remove set status bits from monitored set why ?***/
|
|
ni_priv->monitored_ibsta_bits &= ~ni_usb_ibsta;
|
|
need_monitoring_bits &= ~ni_priv->monitored_ibsta_bits; /* mm - monitored set */
|
|
spin_unlock_irqrestore(&board->spinlock, flags);
|
|
dev_dbg(&usb_dev->dev, "need_monitoring_bits=0x%x\n", need_monitoring_bits);
|
|
|
|
if (need_monitoring_bits & ~ni_usb_ibsta)
|
|
ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask);
|
|
else if (need_monitoring_bits & ni_usb_ibsta)
|
|
wake_up_interruptible(&board->wait);
|
|
|
|
dev_dbg(&usb_dev->dev, "ibsta=0x%x\n", ni_usb_ibsta);
|
|
}
|
|
|
|
static int ni_usb_parse_status_block(const u8 *buffer, struct ni_usb_status_block *status)
|
|
{
|
|
u16 count;
|
|
|
|
status->id = buffer[0];
|
|
status->ibsta = (buffer[1] << 8) | buffer[2];
|
|
status->error_code = buffer[3];
|
|
count = buffer[4] | (buffer[5] << 8);
|
|
count = ~count;
|
|
count++;
|
|
status->count = count;
|
|
return 8;
|
|
};
|
|
|
|
static void ni_usb_dump_raw_block(const u8 *raw_data, int length)
|
|
{
|
|
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 8, 1, raw_data, length, true);
|
|
}
|
|
|
|
static int ni_usb_parse_register_read_block(const u8 *raw_data, unsigned int *results,
|
|
int num_results)
|
|
{
|
|
int i = 0;
|
|
int j;
|
|
int unexpected = 0;
|
|
static const int results_per_chunk = 3;
|
|
|
|
for (j = 0; j < num_results;) {
|
|
int k;
|
|
|
|
if (raw_data[i++] != NIUSB_REGISTER_READ_DATA_START_ID) {
|
|
pr_err("parse error: wrong start id\n");
|
|
unexpected = 1;
|
|
}
|
|
for (k = 0; k < results_per_chunk && j < num_results; ++k)
|
|
results[j++] = raw_data[i++];
|
|
}
|
|
while (i % 4)
|
|
i++;
|
|
if (raw_data[i++] != NIUSB_REGISTER_READ_DATA_END_ID) {
|
|
pr_err("parse error: wrong end id\n");
|
|
unexpected = 1;
|
|
}
|
|
if (raw_data[i++] % results_per_chunk != num_results % results_per_chunk) {
|
|
pr_err("parse error: wrong count=%i for NIUSB_REGISTER_READ_DATA_END\n",
|
|
(int)raw_data[i - 1]);
|
|
unexpected = 1;
|
|
}
|
|
while (i % 4) {
|
|
if (raw_data[i++] != 0) {
|
|
pr_err("unexpected data: raw_data[%i]=0x%x, expected 0\n",
|
|
i - 1, (int)raw_data[i - 1]);
|
|
unexpected = 1;
|
|
}
|
|
}
|
|
if (unexpected)
|
|
ni_usb_dump_raw_block(raw_data, i);
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_parse_termination_block(const u8 *buffer)
|
|
{
|
|
int i = 0;
|
|
|
|
if (buffer[i++] != NIUSB_TERM_ID ||
|
|
buffer[i++] != 0x0 ||
|
|
buffer[i++] != 0x0 ||
|
|
buffer[i++] != 0x0) {
|
|
pr_err("received unexpected termination block\n");
|
|
pr_err(" expected: 0x%x 0x%x 0x%x 0x%x\n", NIUSB_TERM_ID, 0x0, 0x0, 0x0);
|
|
pr_err(" received: 0x%x 0x%x 0x%x 0x%x\n",
|
|
buffer[i - 4], buffer[i - 3], buffer[i - 2], buffer[i - 1]);
|
|
}
|
|
return i;
|
|
};
|
|
|
|
static int parse_board_ibrd_readback(const u8 *raw_data, struct ni_usb_status_block *status,
|
|
u8 *parsed_data, int parsed_data_length,
|
|
int *actual_bytes_read)
|
|
{
|
|
static const int ibrd_data_block_length = 0xf;
|
|
static const int ibrd_extended_data_block_length = 0x1e;
|
|
int data_block_length = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
int k;
|
|
int num_data_blocks = 0;
|
|
struct ni_usb_status_block register_write_status;
|
|
int unexpected = 0;
|
|
|
|
while (raw_data[i] == NIUSB_IBRD_DATA_ID || raw_data[i] == NIUSB_IBRD_EXTENDED_DATA_ID) {
|
|
if (raw_data[i] == NIUSB_IBRD_DATA_ID) {
|
|
data_block_length = ibrd_data_block_length;
|
|
} else if (raw_data[i] == NIUSB_IBRD_EXTENDED_DATA_ID) {
|
|
data_block_length = ibrd_extended_data_block_length;
|
|
if (raw_data[++i] != 0) {
|
|
pr_err("unexpected data: raw_data[%i]=0x%x, expected 0\n",
|
|
i, (int)raw_data[i]);
|
|
unexpected = 1;
|
|
}
|
|
} else {
|
|
pr_err("Unexpected NIUSB_IBRD ID\n");
|
|
return -EINVAL;
|
|
}
|
|
++i;
|
|
for (k = 0; k < data_block_length; k++) {
|
|
if (j < parsed_data_length)
|
|
parsed_data[j++] = raw_data[i++];
|
|
else
|
|
++i;
|
|
}
|
|
++num_data_blocks;
|
|
}
|
|
i += ni_usb_parse_status_block(&raw_data[i], status);
|
|
if (status->id != NIUSB_IBRD_STATUS_ID) {
|
|
pr_err("bug: status->id=%i, != ibrd_status_id\n", status->id);
|
|
return -EIO;
|
|
}
|
|
i++;
|
|
if (num_data_blocks) {
|
|
*actual_bytes_read = (num_data_blocks - 1) * data_block_length + raw_data[i++];
|
|
} else {
|
|
++i;
|
|
*actual_bytes_read = 0;
|
|
}
|
|
if (*actual_bytes_read > j)
|
|
pr_err("bug: discarded data. actual_bytes_read=%i, j=%i\n", *actual_bytes_read, j);
|
|
for (k = 0; k < 2; k++)
|
|
if (raw_data[i++] != 0) {
|
|
pr_err("unexpected data: raw_data[%i]=0x%x, expected 0\n",
|
|
i - 1, (int)raw_data[i - 1]);
|
|
unexpected = 1;
|
|
}
|
|
i += ni_usb_parse_status_block(&raw_data[i], ®ister_write_status);
|
|
if (register_write_status.id != NIUSB_REG_WRITE_ID) {
|
|
pr_err("unexpected data: register write status id=0x%x, expected 0x%x\n",
|
|
register_write_status.id, NIUSB_REG_WRITE_ID);
|
|
unexpected = 1;
|
|
}
|
|
if (raw_data[i++] != 2) {
|
|
pr_err("unexpected data: register write count=%i, expected 2\n",
|
|
(int)raw_data[i - 1]);
|
|
unexpected = 1;
|
|
}
|
|
for (k = 0; k < 3; k++)
|
|
if (raw_data[i++] != 0) {
|
|
pr_err("unexpected data: raw_data[%i]=0x%x, expected 0\n",
|
|
i - 1, (int)raw_data[i - 1]);
|
|
unexpected = 1;
|
|
}
|
|
i += ni_usb_parse_termination_block(&raw_data[i]);
|
|
if (unexpected)
|
|
ni_usb_dump_raw_block(raw_data, i);
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_parse_reg_write_status_block(const u8 *raw_data,
|
|
struct ni_usb_status_block *status,
|
|
int *writes_completed)
|
|
{
|
|
int i = 0;
|
|
|
|
i += ni_usb_parse_status_block(raw_data, status);
|
|
*writes_completed = raw_data[i++];
|
|
while (i % 4)
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_write_registers(struct ni_usb_priv *ni_priv,
|
|
const struct ni_usb_register *writes, int num_writes,
|
|
unsigned int *ibsta)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
u8 *out_data, *in_data;
|
|
int out_data_length;
|
|
static const int in_data_length = 0x20;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
int j;
|
|
struct ni_usb_status_block status;
|
|
static const int bytes_per_write = 3;
|
|
int reg_writes_completed;
|
|
|
|
out_data_length = num_writes * bytes_per_write + 0x10;
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
i += ni_usb_bulk_register_write_header(&out_data[i], num_writes);
|
|
for (j = 0; j < num_writes; j++)
|
|
i += ni_usb_bulk_register_write(&out_data[i], writes[j]);
|
|
while (i % 4)
|
|
out_data[i++] = 0x00;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0);
|
|
if (retval || bytes_read != 16) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
ni_usb_dump_raw_block(in_data, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
ni_usb_parse_reg_write_status_block(in_data, &status, ®_writes_completed);
|
|
// FIXME parse extra 09 status bits and termination
|
|
kfree(in_data);
|
|
if (status.id != NIUSB_REG_WRITE_ID) {
|
|
dev_err(&usb_dev->dev, "parse error, id=0x%x != NIUSB_REG_WRITE_ID\n", status.id);
|
|
return -EIO;
|
|
}
|
|
if (status.error_code) {
|
|
dev_err(&usb_dev->dev, "nonzero error code 0x%x\n", status.error_code);
|
|
return -EIO;
|
|
}
|
|
if (reg_writes_completed != num_writes) {
|
|
dev_err(&usb_dev->dev, "reg_writes_completed=%i, num_writes=%i\n",
|
|
reg_writes_completed, num_writes);
|
|
return -EIO;
|
|
}
|
|
if (ibsta)
|
|
*ibsta = status.ibsta;
|
|
return 0;
|
|
}
|
|
|
|
// interface functions
|
|
static int ni_usb_read(struct gpib_board *board, u8 *buffer, size_t length,
|
|
int *end, size_t *bytes_read)
|
|
{
|
|
int retval, parse_retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x20;
|
|
int in_data_length;
|
|
int usb_bytes_written = 0, usb_bytes_read = 0;
|
|
int i = 0;
|
|
int complement_count;
|
|
int actual_length;
|
|
struct ni_usb_status_block status;
|
|
static const int max_read_length = 0xffff;
|
|
struct ni_usb_register reg;
|
|
|
|
*bytes_read = 0;
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
if (length > max_read_length)
|
|
return -EINVAL;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
out_data[i++] = 0x0a;
|
|
out_data[i++] = ni_priv->eos_mode >> 8;
|
|
out_data[i++] = ni_priv->eos_char;
|
|
out_data[i++] = ni_usb_timeout_code(board->usec_timeout);
|
|
complement_count = length - 1;
|
|
complement_count = ~complement_count;
|
|
out_data[i++] = complement_count & 0xff;
|
|
out_data[i++] = (complement_count >> 8) & 0xff;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_register_write_header(&out_data[i], 2);
|
|
reg.device = NIUSB_SUBDEV_TNT4882;
|
|
reg.address = nec7210_to_tnt4882_offset(AUXMR);
|
|
reg.value = AUX_HLDI;
|
|
i += ni_usb_bulk_register_write(&out_data[i], reg);
|
|
reg.value = AUX_CLEAR_END;
|
|
i += ni_usb_bulk_register_write(&out_data[i], reg);
|
|
while (i % 4) // pad with zeros to 4-byte boundary
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &usb_bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval || usb_bytes_written != i) {
|
|
if (retval == 0)
|
|
retval = -EIO;
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, usb_bytes_written=%i, i=%i\n",
|
|
retval, usb_bytes_written, i);
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return retval;
|
|
}
|
|
|
|
in_data_length = (length / 30 + 1) * 0x20 + 0x20;
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &usb_bytes_read,
|
|
ni_usb_timeout_msecs(board->usec_timeout), 1);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if (retval == -ERESTARTSYS) {
|
|
} else if (retval) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, usb_bytes_read=%i\n",
|
|
retval, usb_bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
parse_retval = parse_board_ibrd_readback(in_data, &status, buffer, length, &actual_length);
|
|
if (parse_retval != usb_bytes_read) {
|
|
if (parse_retval >= 0)
|
|
parse_retval = -EIO;
|
|
dev_err(&usb_dev->dev, "retval=%i usb_bytes_read=%i\n",
|
|
parse_retval, usb_bytes_read);
|
|
kfree(in_data);
|
|
return parse_retval;
|
|
}
|
|
if (actual_length != length - status.count) {
|
|
dev_err(&usb_dev->dev, "actual_length=%i expected=%li\n",
|
|
actual_length, (long)(length - status.count));
|
|
ni_usb_dump_raw_block(in_data, usb_bytes_read);
|
|
}
|
|
kfree(in_data);
|
|
switch (status.error_code) {
|
|
case NIUSB_NO_ERROR:
|
|
retval = 0;
|
|
break;
|
|
case NIUSB_ABORTED_ERROR:
|
|
/*
|
|
* this is expected if ni_usb_receive_bulk_msg got
|
|
* interrupted by a signal and returned -ERESTARTSYS
|
|
*/
|
|
break;
|
|
case NIUSB_ATN_STATE_ERROR:
|
|
if (status.ibsta & DCAS) {
|
|
retval = -EINTR;
|
|
} else {
|
|
retval = -EIO;
|
|
dev_dbg(&usb_dev->dev, "read when ATN set stat: 0x%06x\n", status.ibsta);
|
|
}
|
|
break;
|
|
case NIUSB_ADDRESSING_ERROR:
|
|
retval = -EIO;
|
|
break;
|
|
case NIUSB_TIMEOUT_ERROR:
|
|
retval = -ETIMEDOUT;
|
|
break;
|
|
case NIUSB_EOSMODE_ERROR:
|
|
dev_err(&usb_dev->dev, "driver bug, we should have been able to avoid NIUSB_EOSMODE_ERROR.\n");
|
|
retval = -EINVAL;
|
|
break;
|
|
default:
|
|
dev_err(&usb_dev->dev, "unknown error code=%i\n", status.error_code);
|
|
retval = -EIO;
|
|
break;
|
|
}
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
if (status.ibsta & END)
|
|
*end = 1;
|
|
else
|
|
*end = 0;
|
|
*bytes_read = actual_length;
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_write(struct gpib_board *board, u8 *buffer, size_t length,
|
|
int send_eoi, size_t *bytes_written)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
int out_data_length;
|
|
static const int in_data_length = 0x10;
|
|
int usb_bytes_written = 0, usb_bytes_read = 0;
|
|
int i = 0, j;
|
|
int complement_count;
|
|
struct ni_usb_status_block status;
|
|
static const int max_write_length = 0xffff;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
if (length > max_write_length)
|
|
return -EINVAL;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data_length = length + 0x10;
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
out_data[i++] = 0x0d;
|
|
complement_count = length - 1;
|
|
complement_count = ~complement_count;
|
|
out_data[i++] = complement_count & 0xff;
|
|
out_data[i++] = (complement_count >> 8) & 0xff;
|
|
out_data[i++] = ni_usb_timeout_code(board->usec_timeout);
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
if (send_eoi)
|
|
out_data[i++] = 0x8;
|
|
else
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
for (j = 0; j < length; j++)
|
|
out_data[i++] = buffer[j];
|
|
while (i % 4) // pad with zeros to 4-byte boundary
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &usb_bytes_written,
|
|
ni_usb_timeout_msecs(board->usec_timeout));
|
|
kfree(out_data);
|
|
if (retval || usb_bytes_written != i) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, usb_bytes_written=%i, i=%i\n",
|
|
retval, usb_bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &usb_bytes_read,
|
|
ni_usb_timeout_msecs(board->usec_timeout), 1);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if ((retval && retval != -ERESTARTSYS) || usb_bytes_read != 12) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, usb_bytes_read=%i\n",
|
|
retval, usb_bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
ni_usb_parse_status_block(in_data, &status);
|
|
kfree(in_data);
|
|
switch (status.error_code) {
|
|
case NIUSB_NO_ERROR:
|
|
retval = 0;
|
|
break;
|
|
case NIUSB_ABORTED_ERROR:
|
|
/*
|
|
* this is expected if ni_usb_receive_bulk_msg got
|
|
* interrupted by a signal and returned -ERESTARTSYS
|
|
*/
|
|
break;
|
|
case NIUSB_ADDRESSING_ERROR:
|
|
dev_err(&usb_dev->dev, "Addressing error retval %d error code=%i\n",
|
|
retval, status.error_code);
|
|
retval = -ENXIO;
|
|
break;
|
|
case NIUSB_NO_LISTENER_ERROR:
|
|
retval = -ECOMM;
|
|
break;
|
|
case NIUSB_TIMEOUT_ERROR:
|
|
retval = -ETIMEDOUT;
|
|
break;
|
|
default:
|
|
dev_err(&usb_dev->dev, "unknown error code=%i\n", status.error_code);
|
|
retval = -EPIPE;
|
|
break;
|
|
}
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
*bytes_written = length - status.count;
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_command_chunk(struct gpib_board *board, u8 *buffer, size_t length,
|
|
size_t *command_bytes_written)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
int out_data_length;
|
|
static const int in_data_length = 0x10;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0, j;
|
|
unsigned int complement_count;
|
|
struct ni_usb_status_block status;
|
|
// usb-b gives error 4 if you try to send more than 16 command bytes at once
|
|
static const int max_command_length = 0x10;
|
|
|
|
*command_bytes_written = 0;
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
if (length > max_command_length)
|
|
length = max_command_length;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data_length = length + 0x10;
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
out_data[i++] = 0x0c;
|
|
complement_count = length - 1;
|
|
complement_count = ~complement_count;
|
|
out_data[i++] = complement_count;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = ni_usb_timeout_code(board->usec_timeout);
|
|
for (j = 0; j < length; j++)
|
|
out_data[i++] = buffer[j];
|
|
while (i % 4) // pad with zeros to 4-byte boundary
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written,
|
|
ni_usb_timeout_msecs(board->usec_timeout));
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read,
|
|
ni_usb_timeout_msecs(board->usec_timeout), 1);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if ((retval && retval != -ERESTARTSYS) || bytes_read != 12) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
ni_usb_parse_status_block(in_data, &status);
|
|
kfree(in_data);
|
|
*command_bytes_written = length - status.count;
|
|
switch (status.error_code) {
|
|
case NIUSB_NO_ERROR:
|
|
break;
|
|
case NIUSB_ABORTED_ERROR:
|
|
/*
|
|
* this is expected if ni_usb_receive_bulk_msg got
|
|
* interrupted by a signal and returned -ERESTARTSYS
|
|
*/
|
|
break;
|
|
case NIUSB_NO_BUS_ERROR:
|
|
return -ENOTCONN;
|
|
case NIUSB_EOSMODE_ERROR:
|
|
dev_err(&usb_dev->dev, "got eosmode error. Driver bug?\n");
|
|
return -EIO;
|
|
case NIUSB_TIMEOUT_ERROR:
|
|
return -ETIMEDOUT;
|
|
default:
|
|
dev_err(&usb_dev->dev, "unknown error code=%i\n", status.error_code);
|
|
return -EIO;
|
|
}
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_command(struct gpib_board *board, u8 *buffer, size_t length,
|
|
size_t *bytes_written)
|
|
{
|
|
size_t count;
|
|
int retval;
|
|
|
|
*bytes_written = 0;
|
|
while (*bytes_written < length) {
|
|
retval = ni_usb_command_chunk(board, buffer + *bytes_written,
|
|
length - *bytes_written, &count);
|
|
*bytes_written += count;
|
|
if (retval < 0)
|
|
return retval;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_take_control(struct gpib_board *board, int synchronous)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x10;
|
|
static const int in_data_length = 0x10;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
struct ni_usb_status_block status;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
out_data[i++] = NIUSB_IBCAC_ID;
|
|
if (synchronous)
|
|
out_data[i++] = 0x1;
|
|
else
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 1);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if ((retval && retval != -ERESTARTSYS) || bytes_read != 12) {
|
|
if (retval == 0)
|
|
retval = -EIO;
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
ni_usb_parse_status_block(in_data, &status);
|
|
kfree(in_data);
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_go_to_standby(struct gpib_board *board)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x10;
|
|
static const int in_data_length = 0x20;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
struct ni_usb_status_block status;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
|
|
out_data[i++] = NIUSB_IBGTS_ID;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
|
|
mutex_lock(&ni_priv->addressed_transfer_lock);
|
|
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if (retval || bytes_read != 12) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
ni_usb_parse_status_block(in_data, &status);
|
|
kfree(in_data);
|
|
if (status.id != NIUSB_IBGTS_ID)
|
|
dev_err(&usb_dev->dev, "bug: status.id 0x%x != INUSB_IBGTS_ID\n", status.id);
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_request_system_control(struct gpib_board *board, int request_control)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[4];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
if (request_control) {
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = CMDR;
|
|
writes[i].value = SETSC;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CIFC;
|
|
i++;
|
|
} else {
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CREN;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CIFC;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_DSC;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = CMDR;
|
|
writes[i].value = CLRSC;
|
|
i++;
|
|
}
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
if (!request_control)
|
|
ni_priv->ren_state = 0;
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
// FIXME maybe the interface should have a "pulse interface clear" function that can return an error?
|
|
static void ni_usb_interface_clear(struct gpib_board *board, int assert)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x10;
|
|
static const int in_data_length = 0x10;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
struct ni_usb_status_block status;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
// FIXME: we are going to pulse when assert is true, and ignore otherwise
|
|
if (assert == 0)
|
|
return;
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return;
|
|
out_data[i++] = NIUSB_IBSIC_ID;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return;
|
|
}
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data)
|
|
return;
|
|
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0);
|
|
if (retval || bytes_read != 12) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return;
|
|
}
|
|
ni_usb_parse_status_block(in_data, &status);
|
|
kfree(in_data);
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
}
|
|
|
|
static void ni_usb_remote_enable(struct gpib_board *board, int enable)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
struct ni_usb_register reg;
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
reg.device = NIUSB_SUBDEV_TNT4882;
|
|
reg.address = nec7210_to_tnt4882_offset(AUXMR);
|
|
if (enable)
|
|
reg.value = AUX_SREN;
|
|
else
|
|
reg.value = AUX_CREN;
|
|
retval = ni_usb_write_registers(ni_priv, ®, 1, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return; //retval;
|
|
}
|
|
ni_priv->ren_state = enable;
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return;// 0;
|
|
}
|
|
|
|
static int ni_usb_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
|
|
{
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
|
|
ni_priv->eos_char = eos_byte;
|
|
ni_priv->eos_mode |= REOS;
|
|
if (compare_8_bits)
|
|
ni_priv->eos_mode |= BIN;
|
|
else
|
|
ni_priv->eos_mode &= ~BIN;
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_disable_eos(struct gpib_board *board)
|
|
{
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
/*
|
|
* adapter gets unhappy if you don't zero all the bits
|
|
* for the eos mode and eos char (returns error 4 on reads).
|
|
*/
|
|
ni_priv->eos_mode = 0;
|
|
ni_priv->eos_char = 0;
|
|
}
|
|
|
|
static unsigned int ni_usb_update_status(struct gpib_board *board, unsigned int clear_mask)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
static const int buffer_length = 8;
|
|
u8 *buffer;
|
|
struct ni_usb_status_block status;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
buffer = kmalloc(buffer_length, GFP_KERNEL);
|
|
if (!buffer)
|
|
return board->status;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_WAIT_REQUEST, USB_DIR_IN |
|
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x200, 0x0, buffer, buffer_length, 1000);
|
|
if (retval != buffer_length) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg returned %i\n", retval);
|
|
kfree(buffer);
|
|
return board->status;
|
|
}
|
|
ni_usb_parse_status_block(buffer, &status);
|
|
kfree(buffer);
|
|
ni_usb_soft_update_status(board, status.ibsta, clear_mask);
|
|
return board->status;
|
|
}
|
|
|
|
// tells ni-usb to immediately stop an ongoing i/o operation
|
|
static void ni_usb_stop(struct ni_usb_priv *ni_priv)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
static const int buffer_length = 8;
|
|
u8 *buffer;
|
|
struct ni_usb_status_block status;
|
|
|
|
buffer = kmalloc(buffer_length, GFP_KERNEL);
|
|
if (!buffer)
|
|
return;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_STOP_REQUEST, USB_DIR_IN |
|
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x0, 0x0, buffer, buffer_length, 1000);
|
|
if (retval != buffer_length) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg returned %i\n", retval);
|
|
kfree(buffer);
|
|
return;
|
|
}
|
|
ni_usb_parse_status_block(buffer, &status);
|
|
kfree(buffer);
|
|
}
|
|
|
|
static int ni_usb_primary_address(struct gpib_board *board, unsigned int address)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[2];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(ADR);
|
|
writes[i].value = address;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_UNKNOWN2;
|
|
writes[i].address = 0x0;
|
|
writes[i].value = address;
|
|
i++;
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_write_sad(struct ni_usb_register *writes, int address, int enable)
|
|
{
|
|
unsigned int adr_bits, admr_bits;
|
|
int i = 0;
|
|
|
|
adr_bits = HR_ARS;
|
|
admr_bits = HR_TRM0 | HR_TRM1;
|
|
if (enable) {
|
|
adr_bits |= address;
|
|
admr_bits |= HR_ADM1;
|
|
} else {
|
|
adr_bits |= HR_DT | HR_DL;
|
|
admr_bits |= HR_ADM0;
|
|
}
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(ADR);
|
|
writes[i].value = adr_bits;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(ADMR);
|
|
writes[i].value = admr_bits;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_UNKNOWN2;
|
|
writes[i].address = 0x1;
|
|
writes[i].value = enable ? MSA(address) : 0x0;
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_secondary_address(struct gpib_board *board, unsigned int address, int enable)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[3];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
i += ni_usb_write_sad(writes, address, enable);
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_parallel_poll(struct gpib_board *board, u8 *result)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x10;
|
|
static const int in_data_length = 0x20;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
struct ni_usb_status_block status;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
|
|
out_data[i++] = NIUSB_IBRPP_ID;
|
|
out_data[i++] = 0xf0; // FIXME: this should be the parallel poll timeout code
|
|
out_data[i++] = 0x0;
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
/*FIXME: 1000 should use parallel poll timeout (not supported yet)*/
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data)
|
|
return -ENOMEM;
|
|
|
|
/*FIXME: should use parallel poll timeout (not supported yet)*/
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length,
|
|
&bytes_read, 1000, 1);
|
|
|
|
if (retval && retval != -ERESTARTSYS) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
j += ni_usb_parse_status_block(in_data, &status);
|
|
*result = in_data[j++];
|
|
kfree(in_data);
|
|
ni_usb_soft_update_status(board, status.ibsta, 0);
|
|
return retval;
|
|
}
|
|
|
|
static void ni_usb_parallel_poll_configure(struct gpib_board *board, u8 config)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[1];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = PPR | config;
|
|
i++;
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return;// retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return;// 0;
|
|
}
|
|
|
|
static void ni_usb_parallel_poll_response(struct gpib_board *board, int ist)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[1];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
if (ist)
|
|
writes[i].value = AUX_SPPF;
|
|
else
|
|
writes[i].value = AUX_CPPF;
|
|
i++;
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return;// retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return;// 0;
|
|
}
|
|
|
|
static void ni_usb_serial_poll_response(struct gpib_board *board, u8 status)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[1];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(SPMR);
|
|
writes[i].value = status;
|
|
i++;
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return;// retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return;// 0;
|
|
}
|
|
|
|
static u8 ni_usb_serial_poll_status(struct gpib_board *board)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_return_to_local(struct gpib_board *board)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int i = 0;
|
|
struct ni_usb_register writes[1];
|
|
unsigned int ibsta;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return; // -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_RTL;
|
|
i++;
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return;// retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return;// 0;
|
|
}
|
|
|
|
static int ni_usb_line_status(const struct gpib_board *board)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
u8 *out_data, *in_data;
|
|
static const int out_data_length = 0x20;
|
|
static const int in_data_length = 0x20;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
unsigned int bsr_bits;
|
|
int line_status = VALID_ALL;
|
|
// NI windows driver reads 0xd(HSSEL), 0xc (ARD0), 0x1f (BSR)
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data)
|
|
return -ENOMEM;
|
|
|
|
/* line status gets called during ibwait */
|
|
retval = mutex_trylock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if (retval == 0) {
|
|
kfree(out_data);
|
|
return -EBUSY;
|
|
}
|
|
i += ni_usb_bulk_register_read_header(&out_data[i], 1);
|
|
i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_TNT4882, BSR);
|
|
while (i % 4)
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000);
|
|
kfree(out_data);
|
|
if (retval || bytes_written != i) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
if (retval != -EAGAIN)
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%i\n",
|
|
retval, bytes_written, i);
|
|
return retval;
|
|
}
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data) {
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, in_data, in_data_length,
|
|
&bytes_read, 1000, 0);
|
|
|
|
mutex_unlock(&ni_priv->addressed_transfer_lock);
|
|
|
|
if (retval) {
|
|
if (retval != -EAGAIN)
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
kfree(in_data);
|
|
return retval;
|
|
}
|
|
|
|
ni_usb_parse_register_read_block(in_data, &bsr_bits, 1);
|
|
kfree(in_data);
|
|
if (bsr_bits & BCSR_REN_BIT)
|
|
line_status |= BUS_REN;
|
|
if (bsr_bits & BCSR_IFC_BIT)
|
|
line_status |= BUS_IFC;
|
|
if (bsr_bits & BCSR_SRQ_BIT)
|
|
line_status |= BUS_SRQ;
|
|
if (bsr_bits & BCSR_EOI_BIT)
|
|
line_status |= BUS_EOI;
|
|
if (bsr_bits & BCSR_NRFD_BIT)
|
|
line_status |= BUS_NRFD;
|
|
if (bsr_bits & BCSR_NDAC_BIT)
|
|
line_status |= BUS_NDAC;
|
|
if (bsr_bits & BCSR_DAV_BIT)
|
|
line_status |= BUS_DAV;
|
|
if (bsr_bits & BCSR_ATN_BIT)
|
|
line_status |= BUS_ATN;
|
|
return line_status;
|
|
}
|
|
|
|
static int ni_usb_setup_t1_delay(struct ni_usb_register *reg, unsigned int nano_sec,
|
|
unsigned int *actual_ns)
|
|
{
|
|
int i = 0;
|
|
|
|
*actual_ns = 2000;
|
|
|
|
reg[i].device = NIUSB_SUBDEV_TNT4882;
|
|
reg[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
if (nano_sec <= 1100) {
|
|
reg[i].value = AUXRI | USTD | SISB;
|
|
*actual_ns = 1100;
|
|
} else {
|
|
reg[i].value = AUXRI | SISB;
|
|
}
|
|
i++;
|
|
reg[i].device = NIUSB_SUBDEV_TNT4882;
|
|
reg[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
if (nano_sec <= 500) {
|
|
reg[i].value = AUXRB | HR_TRI;
|
|
*actual_ns = 500;
|
|
} else {
|
|
reg[i].value = AUXRB;
|
|
}
|
|
i++;
|
|
reg[i].device = NIUSB_SUBDEV_TNT4882;
|
|
reg[i].address = KEYREG;
|
|
if (nano_sec <= 350) {
|
|
reg[i].value = MSTD;
|
|
*actual_ns = 350;
|
|
} else {
|
|
reg[i].value = 0x0;
|
|
}
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_t1_delay(struct gpib_board *board, unsigned int nano_sec)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
struct ni_usb_register writes[3];
|
|
unsigned int ibsta;
|
|
unsigned int actual_ns;
|
|
int i;
|
|
|
|
if (!ni_priv->bus_interface)
|
|
return -ENODEV;
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
i = ni_usb_setup_t1_delay(writes, nano_sec, &actual_ns);
|
|
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
board->t1_nano_sec = actual_ns;
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return actual_ns;
|
|
}
|
|
|
|
static int ni_usb_allocate_private(struct gpib_board *board)
|
|
{
|
|
struct ni_usb_priv *ni_priv;
|
|
|
|
board->private_data = kmalloc(sizeof(struct ni_usb_priv), GFP_KERNEL);
|
|
if (!board->private_data)
|
|
return -ENOMEM;
|
|
ni_priv = board->private_data;
|
|
memset(ni_priv, 0, sizeof(struct ni_usb_priv));
|
|
mutex_init(&ni_priv->bulk_transfer_lock);
|
|
mutex_init(&ni_priv->control_transfer_lock);
|
|
mutex_init(&ni_priv->interrupt_transfer_lock);
|
|
mutex_init(&ni_priv->addressed_transfer_lock);
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_free_private(struct ni_usb_priv *ni_priv)
|
|
{
|
|
usb_free_urb(ni_priv->interrupt_urb);
|
|
kfree(ni_priv);
|
|
}
|
|
|
|
#define NUM_INIT_WRITES 26
|
|
static int ni_usb_setup_init(struct gpib_board *board, struct ni_usb_register *writes)
|
|
{
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
unsigned int mask, actual_ns;
|
|
int i = 0;
|
|
|
|
writes[i].device = NIUSB_SUBDEV_UNKNOWN3;
|
|
writes[i].address = 0x10;
|
|
writes[i].value = 0x0;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = CMDR;
|
|
writes[i].value = SOFT_RESET;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
mask = AUXRA | HR_HLDA;
|
|
if (ni_priv->eos_mode & BIN)
|
|
mask |= HR_BIN;
|
|
writes[i].value = mask;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = AUXCR;
|
|
writes[i].value = mask;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = HSSEL;
|
|
writes[i].value = TNT_ONE_CHIP_BIT;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CR;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = IMR0;
|
|
writes[i].value = TNT_IMR0_ALWAYS_BITS;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(IMR1);
|
|
writes[i].value = 0x0;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(IMR2);
|
|
writes[i].value = 0x0;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = IMR3;
|
|
writes[i].value = 0x0;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_HLDI;
|
|
i++;
|
|
|
|
i += ni_usb_setup_t1_delay(&writes[i], board->t1_nano_sec, &actual_ns);
|
|
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUXRG | NTNL_BIT;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = CMDR;
|
|
if (board->master)
|
|
mask = SETSC; // set system controller
|
|
else
|
|
mask = CLRSC; // clear system controller
|
|
writes[i].value = mask;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CIFC;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(ADR);
|
|
writes[i].value = board->pad;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_UNKNOWN2;
|
|
writes[i].address = 0x0;
|
|
writes[i].value = board->pad;
|
|
i++;
|
|
|
|
i += ni_usb_write_sad(&writes[i], board->sad, board->sad >= 0);
|
|
|
|
writes[i].device = NIUSB_SUBDEV_UNKNOWN2;
|
|
writes[i].address = 0x2; // could this be a timeout ?
|
|
writes[i].value = 0xfd;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = 0xf; // undocumented address
|
|
writes[i].value = 0x11;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_PON;
|
|
i++;
|
|
writes[i].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[i].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[i].value = AUX_CPPF;
|
|
i++;
|
|
if (i > NUM_INIT_WRITES) {
|
|
dev_err(&usb_dev->dev, "bug!, buffer overrun, i=%i\n", i);
|
|
return 0;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static int ni_usb_init(struct gpib_board *board)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
struct ni_usb_register *writes;
|
|
unsigned int ibsta;
|
|
int writes_len;
|
|
|
|
writes = kmalloc_array(NUM_INIT_WRITES, sizeof(*writes), GFP_KERNEL);
|
|
if (!writes)
|
|
return -ENOMEM;
|
|
|
|
writes_len = ni_usb_setup_init(board, writes);
|
|
if (writes_len)
|
|
retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta);
|
|
else
|
|
return -EFAULT;
|
|
kfree(writes);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
ni_usb_soft_update_status(board, ibsta, 0);
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_interrupt_complete(struct urb *urb)
|
|
{
|
|
struct gpib_board *board = urb->context;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
struct ni_usb_status_block status;
|
|
unsigned long flags;
|
|
|
|
switch (urb->status) {
|
|
/* success */
|
|
case 0:
|
|
break;
|
|
/* unlinked, don't resubmit */
|
|
case -ECONNRESET:
|
|
case -ENOENT:
|
|
case -ESHUTDOWN:
|
|
return;
|
|
default: /* other error, resubmit */
|
|
retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_ATOMIC);
|
|
if (retval)
|
|
dev_err(&usb_dev->dev, "failed to resubmit interrupt urb\n");
|
|
return;
|
|
}
|
|
|
|
ni_usb_parse_status_block(urb->transfer_buffer, &status);
|
|
|
|
spin_lock_irqsave(&board->spinlock, flags);
|
|
ni_priv->monitored_ibsta_bits &= ~status.ibsta;
|
|
spin_unlock_irqrestore(&board->spinlock, flags);
|
|
|
|
wake_up_interruptible(&board->wait);
|
|
|
|
retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_ATOMIC);
|
|
if (retval)
|
|
dev_err(&usb_dev->dev, "failed to resubmit interrupt urb\n");
|
|
}
|
|
|
|
static int ni_usb_set_interrupt_monitor(struct gpib_board *board, unsigned int monitored_bits)
|
|
{
|
|
int retval;
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
static const int buffer_length = 8;
|
|
u8 *buffer;
|
|
struct ni_usb_status_block status;
|
|
unsigned long flags;
|
|
|
|
buffer = kmalloc(buffer_length, GFP_KERNEL);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
spin_lock_irqsave(&board->spinlock, flags);
|
|
ni_priv->monitored_ibsta_bits = ni_usb_ibsta_monitor_mask & monitored_bits;
|
|
spin_unlock_irqrestore(&board->spinlock, flags);
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_WAIT_REQUEST, USB_DIR_IN |
|
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x300, ni_usb_ibsta_monitor_mask & monitored_bits,
|
|
buffer, buffer_length, 1000);
|
|
if (retval != buffer_length) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg returned %i\n", retval);
|
|
kfree(buffer);
|
|
return -1;
|
|
}
|
|
ni_usb_parse_status_block(buffer, &status);
|
|
kfree(buffer);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_setup_urbs(struct gpib_board *board)
|
|
{
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
struct usb_device *usb_dev;
|
|
int int_pipe;
|
|
int retval;
|
|
|
|
if (ni_priv->interrupt_in_endpoint < 0)
|
|
return 0;
|
|
|
|
mutex_lock(&ni_priv->interrupt_transfer_lock);
|
|
if (!ni_priv->bus_interface) {
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
return -ENODEV;
|
|
}
|
|
ni_priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (!ni_priv->interrupt_urb) {
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
return -ENOMEM;
|
|
}
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int_pipe = usb_rcvintpipe(usb_dev, ni_priv->interrupt_in_endpoint);
|
|
usb_fill_int_urb(ni_priv->interrupt_urb, usb_dev, int_pipe, ni_priv->interrupt_buffer,
|
|
sizeof(ni_priv->interrupt_buffer), &ni_usb_interrupt_complete, board, 1);
|
|
retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_KERNEL);
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "failed to submit first interrupt urb, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_cleanup_urbs(struct ni_usb_priv *ni_priv)
|
|
{
|
|
if (ni_priv && ni_priv->bus_interface) {
|
|
if (ni_priv->interrupt_urb)
|
|
usb_kill_urb(ni_priv->interrupt_urb);
|
|
if (ni_priv->bulk_urb)
|
|
usb_kill_urb(ni_priv->bulk_urb);
|
|
}
|
|
}
|
|
|
|
static int ni_usb_b_read_serial_number(struct ni_usb_priv *ni_priv)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
u8 *out_data;
|
|
u8 *in_data;
|
|
static const int out_data_length = 0x20;
|
|
static const int in_data_length = 0x20;
|
|
int bytes_written = 0, bytes_read = 0;
|
|
int i = 0;
|
|
static const int num_reads = 4;
|
|
unsigned int results[4];
|
|
int j;
|
|
unsigned int serial_number;
|
|
|
|
in_data = kmalloc(in_data_length, GFP_KERNEL);
|
|
if (!in_data)
|
|
return -ENOMEM;
|
|
|
|
out_data = kmalloc(out_data_length, GFP_KERNEL);
|
|
if (!out_data) {
|
|
kfree(in_data);
|
|
return -ENOMEM;
|
|
}
|
|
i += ni_usb_bulk_register_read_header(&out_data[i], num_reads);
|
|
i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_1_REG);
|
|
i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_2_REG);
|
|
i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_3_REG);
|
|
i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_4_REG);
|
|
while (i % 4)
|
|
out_data[i++] = 0x0;
|
|
i += ni_usb_bulk_termination(&out_data[i]);
|
|
retval = ni_usb_send_bulk_msg(ni_priv, out_data, out_data_length, &bytes_written, 1000);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "send_bulk_msg returned %i, bytes_written=%i, i=%li\n",
|
|
retval, bytes_written, (long)out_data_length);
|
|
goto serial_out;
|
|
}
|
|
retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "receive_bulk_msg returned %i, bytes_read=%i\n",
|
|
retval, bytes_read);
|
|
ni_usb_dump_raw_block(in_data, bytes_read);
|
|
goto serial_out;
|
|
}
|
|
if (ARRAY_SIZE(results) < num_reads) {
|
|
dev_err(&usb_dev->dev, "serial number eetup bug\n");
|
|
retval = -EINVAL;
|
|
goto serial_out;
|
|
}
|
|
ni_usb_parse_register_read_block(in_data, results, num_reads);
|
|
serial_number = 0;
|
|
for (j = 0; j < num_reads; ++j)
|
|
serial_number |= (results[j] & 0xff) << (8 * j);
|
|
dev_dbg(&usb_dev->dev, "board serial number is 0x%x\n", serial_number);
|
|
retval = 0;
|
|
serial_out:
|
|
kfree(in_data);
|
|
kfree(out_data);
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
static const int buffer_size = 0x10;
|
|
static const int timeout = 50;
|
|
static const int msec_sleep_duration = 100;
|
|
int i; int retval;
|
|
int j;
|
|
int unexpected = 0;
|
|
unsigned int serial_number;
|
|
u8 *buffer;
|
|
|
|
buffer = kmalloc(buffer_size, GFP_KERNEL);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_SERIAL_NUMBER_REQUEST,
|
|
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x0, 0x0, buffer, buffer_size, 1000);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg request 0x%x returned %i\n",
|
|
NI_USB_SERIAL_NUMBER_REQUEST, retval);
|
|
goto ready_out;
|
|
}
|
|
j = 0;
|
|
if (buffer[j] != NI_USB_SERIAL_NUMBER_REQUEST) {
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x%x\n",
|
|
j, (int)buffer[j], NI_USB_SERIAL_NUMBER_REQUEST);
|
|
unexpected = 1;
|
|
}
|
|
if (unexpected)
|
|
ni_usb_dump_raw_block(buffer, retval);
|
|
// NI-USB-HS+ pads the serial with 0x0 to make 16 bytes
|
|
if (retval != 5 && retval != 16) {
|
|
dev_err(&usb_dev->dev, "received unexpected number of bytes = %i, expected 5 or 16\n",
|
|
retval);
|
|
ni_usb_dump_raw_block(buffer, retval);
|
|
}
|
|
serial_number = 0;
|
|
serial_number |= buffer[++j];
|
|
serial_number |= (buffer[++j] << 8);
|
|
serial_number |= (buffer[++j] << 16);
|
|
serial_number |= (buffer[++j] << 24);
|
|
dev_dbg(&usb_dev->dev, "board serial number is 0x%x\n", serial_number);
|
|
for (i = 0; i < timeout; ++i) {
|
|
int ready = 0;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_POLL_READY_REQUEST,
|
|
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x0, 0x0, buffer, buffer_size, 100);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg request 0x%x returned %i\n",
|
|
NI_USB_POLL_READY_REQUEST, retval);
|
|
goto ready_out;
|
|
}
|
|
j = 0;
|
|
unexpected = 0;
|
|
if (buffer[j] != NI_USB_POLL_READY_REQUEST) { // [0]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x%x\n",
|
|
j, (int)buffer[j], NI_USB_POLL_READY_REQUEST);
|
|
unexpected = 1;
|
|
}
|
|
++j;
|
|
if (buffer[j] != 0x1 && buffer[j] != 0x0) { // [1] HS+ sends 0x0
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x1 or 0x0\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
if (buffer[++j] != 0x0) { // [2]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x%x\n",
|
|
j, (int)buffer[j], 0x0);
|
|
unexpected = 1;
|
|
}
|
|
++j;
|
|
/*
|
|
* MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here
|
|
* NI-USB-HS+ sends 0x0
|
|
*/
|
|
if (buffer[j] != 0x1 && buffer[j] != 0x8 && buffer[j] != 0x7 && buffer[j] != 0x0) {
|
|
// [3]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x0, 0x1, 0x7 or 0x8\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
++j;
|
|
// NI-USB-HS+ sends 0 here
|
|
if (buffer[j] != 0x30 && buffer[j] != 0x0) { // [4]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x0 or 0x30\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
++j;
|
|
// MC usb-488 (and sometimes NI-USB-HS?) and NI-USB-HS+ sends 0x0 here
|
|
if (buffer[j] != 0x1 && buffer[j] != 0x0) { // [5]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x1 or 0x0\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
if (buffer[++j] != 0x0) { // [6]
|
|
ready = 1;
|
|
// NI-USB-HS+ sends 0xf or 0x19 here
|
|
if (buffer[j] != 0x2 && buffer[j] != 0xe && buffer[j] != 0xf &&
|
|
buffer[j] != 0x16 && buffer[j] != 0x19) {
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x2, 0xe, 0xf, 0x16 or 0x19\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
}
|
|
if (buffer[++j] != 0x0) { // [7]
|
|
ready = 1;
|
|
// MC usb-488 sends 0x5 here; MC usb-488A sends 0x6 here
|
|
if (buffer[j] != 0x3 && buffer[j] != 0x5 && buffer[j] != 0x6 &&
|
|
buffer[j] != 0x8) {
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x3 or 0x5, 0x6 or 0x08\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
}
|
|
++j;
|
|
if (buffer[j] != 0x0 && buffer[j] != 0x2) { // [8] MC usb-488 sends 0x2 here
|
|
dev_err(&usb_dev->dev, " unexpected data: buffer[%i]=0x%x, expected 0x0 or 0x2\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
++j;
|
|
// MC usb-488A and NI-USB-HS sends 0x3 here; NI-USB-HS+ sends 0x30 here
|
|
if (buffer[j] != 0x0 && buffer[j] != 0x3 && buffer[j] != 0x30) { // [9]
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x0, 0x3 or 0x30\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
if (buffer[++j] != 0x0) { // [10] MC usb-488 sends 0x7 here, new HS+ sends 0x59
|
|
ready = 1;
|
|
if (buffer[j] != 0x96 && buffer[j] != 0x7 && buffer[j] != 0x6e &&
|
|
buffer[j] != 0x59) {
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x96, 0x07, 0x6e or 0x59\n",
|
|
j, (int)buffer[j]);
|
|
unexpected = 1;
|
|
}
|
|
}
|
|
if (unexpected)
|
|
ni_usb_dump_raw_block(buffer, retval);
|
|
if (ready)
|
|
break;
|
|
retval = msleep_interruptible(msec_sleep_duration);
|
|
if (retval) {
|
|
retval = -ERESTARTSYS;
|
|
goto ready_out;
|
|
}
|
|
}
|
|
retval = 0;
|
|
|
|
ready_out:
|
|
kfree(buffer);
|
|
dev_dbg(&usb_dev->dev, "exit retval=%d\n", retval);
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* This does some extra init for HS+ models, as observed on Windows. One of the
|
|
* control requests causes the LED to stop blinking.
|
|
* I'm not sure what the other 2 requests do. None of these requests are actually required
|
|
* for the adapter to work, maybe they do some init for the analyzer interface
|
|
* (which we don't use).
|
|
*/
|
|
static int ni_usb_hs_plus_extra_init(struct ni_usb_priv *ni_priv)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
u8 *buffer;
|
|
static const int buffer_size = 16;
|
|
int transfer_size;
|
|
|
|
buffer = kmalloc(buffer_size, GFP_KERNEL);
|
|
if (!buffer)
|
|
return -ENOMEM;
|
|
do {
|
|
transfer_size = 16;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_0x48_REQUEST,
|
|
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x0, 0x0, buffer, transfer_size, 1000);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg request 0x%x returned %i\n",
|
|
NI_USB_HS_PLUS_0x48_REQUEST, retval);
|
|
break;
|
|
}
|
|
// expected response data: 48 f3 30 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
if (buffer[0] != NI_USB_HS_PLUS_0x48_REQUEST)
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[0]=0x%x, expected 0x%x\n",
|
|
(int)buffer[0], NI_USB_HS_PLUS_0x48_REQUEST);
|
|
|
|
transfer_size = 2;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_LED_REQUEST,
|
|
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
0x1, 0x0, buffer, transfer_size, 1000);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg request 0x%x returned %i\n",
|
|
NI_USB_HS_PLUS_LED_REQUEST, retval);
|
|
break;
|
|
}
|
|
// expected response data: 4b 00
|
|
if (buffer[0] != NI_USB_HS_PLUS_LED_REQUEST)
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[0]=0x%x, expected 0x%x\n",
|
|
(int)buffer[0], NI_USB_HS_PLUS_LED_REQUEST);
|
|
|
|
transfer_size = 9;
|
|
|
|
retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_0xf8_REQUEST,
|
|
USB_DIR_IN | USB_TYPE_VENDOR |
|
|
USB_RECIP_INTERFACE,
|
|
0x0, 0x1, buffer, transfer_size, 1000);
|
|
if (retval < 0) {
|
|
dev_err(&usb_dev->dev, "usb_control_msg request 0x%x returned %i\n",
|
|
NI_USB_HS_PLUS_0xf8_REQUEST, retval);
|
|
break;
|
|
}
|
|
// expected response data: f8 01 00 00 00 01 00 00 00
|
|
if (buffer[0] != NI_USB_HS_PLUS_0xf8_REQUEST)
|
|
dev_err(&usb_dev->dev, "unexpected data: buffer[0]=0x%x, expected 0x%x\n",
|
|
(int)buffer[0], NI_USB_HS_PLUS_0xf8_REQUEST);
|
|
} while (0);
|
|
|
|
// cleanup
|
|
kfree(buffer);
|
|
return retval;
|
|
}
|
|
|
|
static inline int ni_usb_device_match(struct usb_interface *interface,
|
|
const struct gpib_board_config *config)
|
|
{
|
|
if (gpib_match_device_path(&interface->dev, config->device_path) == 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
static int ni_usb_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
int retval;
|
|
int i, index;
|
|
struct ni_usb_priv *ni_priv;
|
|
int product_id;
|
|
struct usb_device *usb_dev;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
retval = ni_usb_allocate_private(board);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
ni_priv = board->private_data;
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) {
|
|
if (ni_usb_driver_interfaces[i] &&
|
|
!usb_get_intfdata(ni_usb_driver_interfaces[i]) &&
|
|
ni_usb_device_match(ni_usb_driver_interfaces[i], config)) {
|
|
ni_priv->bus_interface = ni_usb_driver_interfaces[i];
|
|
usb_set_intfdata(ni_usb_driver_interfaces[i], board);
|
|
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_NUM_NI_USB_INTERFACES) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
dev_err(board->gpib_dev, "No supported adapters found, have you loaded its firmware?\n");
|
|
return -ENODEV;
|
|
}
|
|
if (usb_reset_configuration(interface_to_usbdev(ni_priv->bus_interface)))
|
|
dev_err(&usb_dev->dev, "usb_reset_configuration() failed.\n");
|
|
|
|
product_id = le16_to_cpu(usb_dev->descriptor.idProduct);
|
|
ni_priv->product_id = product_id;
|
|
|
|
timer_setup(&ni_priv->bulk_timer, ni_usb_timeout_handler, 0);
|
|
|
|
switch (product_id) {
|
|
case USB_DEVICE_ID_NI_USB_B:
|
|
ni_priv->bulk_out_endpoint = NIUSB_B_BULK_OUT_ENDPOINT;
|
|
ni_priv->bulk_in_endpoint = NIUSB_B_BULK_IN_ENDPOINT;
|
|
ni_priv->interrupt_in_endpoint = NIUSB_B_INTERRUPT_IN_ENDPOINT;
|
|
ni_usb_b_read_serial_number(ni_priv);
|
|
break;
|
|
case USB_DEVICE_ID_NI_USB_HS:
|
|
case USB_DEVICE_ID_MC_USB_488:
|
|
case USB_DEVICE_ID_KUSB_488A:
|
|
ni_priv->bulk_out_endpoint = NIUSB_HS_BULK_OUT_ENDPOINT;
|
|
ni_priv->bulk_in_endpoint = NIUSB_HS_BULK_IN_ENDPOINT;
|
|
ni_priv->interrupt_in_endpoint = NIUSB_HS_INTERRUPT_IN_ENDPOINT;
|
|
retval = ni_usb_hs_wait_for_ready(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
break;
|
|
case USB_DEVICE_ID_NI_USB_HS_PLUS:
|
|
ni_priv->bulk_out_endpoint = NIUSB_HS_PLUS_BULK_OUT_ENDPOINT;
|
|
ni_priv->bulk_in_endpoint = NIUSB_HS_PLUS_BULK_IN_ENDPOINT;
|
|
ni_priv->interrupt_in_endpoint = NIUSB_HS_PLUS_INTERRUPT_IN_ENDPOINT;
|
|
retval = ni_usb_hs_wait_for_ready(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
retval = ni_usb_hs_plus_extra_init(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
break;
|
|
default:
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
dev_err(&usb_dev->dev, "\tDriver bug: unknown endpoints for usb device id %x\n",
|
|
product_id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
retval = ni_usb_setup_urbs(board);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
retval = ni_usb_set_interrupt_monitor(board, 0);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
|
|
board->t1_nano_sec = 500;
|
|
|
|
retval = ni_usb_init(board);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
retval = ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
dev_info(&usb_dev->dev,
|
|
"bus %d dev num %d attached to gpib%d, intf %i\n",
|
|
usb_dev->bus->busnum, usb_dev->devnum, board->minor, index);
|
|
return retval;
|
|
}
|
|
|
|
static int ni_usb_shutdown_hardware(struct ni_usb_priv *ni_priv)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface);
|
|
int retval;
|
|
struct ni_usb_register writes[2];
|
|
static const int writes_length = ARRAY_SIZE(writes);
|
|
unsigned int ibsta;
|
|
|
|
writes[0].device = NIUSB_SUBDEV_TNT4882;
|
|
writes[0].address = nec7210_to_tnt4882_offset(AUXMR);
|
|
writes[0].value = AUX_CR;
|
|
writes[1].device = NIUSB_SUBDEV_UNKNOWN3;
|
|
writes[1].address = 0x10;
|
|
writes[1].value = 0x0;
|
|
retval = ni_usb_write_registers(ni_priv, writes, writes_length, &ibsta);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
|
|
return retval;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_detach(struct gpib_board *board)
|
|
{
|
|
struct ni_usb_priv *ni_priv;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
/*
|
|
* under windows, software unplug does chip_reset nec7210 aux command,
|
|
* then writes 0x0 to address 0x10 of device 3
|
|
*/
|
|
ni_priv = board->private_data;
|
|
if (ni_priv) {
|
|
if (ni_priv->bus_interface) {
|
|
ni_usb_set_interrupt_monitor(board, 0);
|
|
ni_usb_shutdown_hardware(ni_priv);
|
|
usb_set_intfdata(ni_priv->bus_interface, NULL);
|
|
}
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
mutex_lock(&ni_priv->control_transfer_lock);
|
|
mutex_lock(&ni_priv->interrupt_transfer_lock);
|
|
ni_usb_cleanup_urbs(ni_priv);
|
|
ni_usb_free_private(ni_priv);
|
|
}
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
}
|
|
|
|
static struct gpib_interface ni_usb_gpib_interface = {
|
|
.name = "ni_usb_b",
|
|
.attach = ni_usb_attach,
|
|
.detach = ni_usb_detach,
|
|
.read = ni_usb_read,
|
|
.write = ni_usb_write,
|
|
.command = ni_usb_command,
|
|
.take_control = ni_usb_take_control,
|
|
.go_to_standby = ni_usb_go_to_standby,
|
|
.request_system_control = ni_usb_request_system_control,
|
|
.interface_clear = ni_usb_interface_clear,
|
|
.remote_enable = ni_usb_remote_enable,
|
|
.enable_eos = ni_usb_enable_eos,
|
|
.disable_eos = ni_usb_disable_eos,
|
|
.parallel_poll = ni_usb_parallel_poll,
|
|
.parallel_poll_configure = ni_usb_parallel_poll_configure,
|
|
.parallel_poll_response = ni_usb_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ni_usb_line_status,
|
|
.update_status = ni_usb_update_status,
|
|
.primary_address = ni_usb_primary_address,
|
|
.secondary_address = ni_usb_secondary_address,
|
|
.serial_poll_response = ni_usb_serial_poll_response,
|
|
.serial_poll_status = ni_usb_serial_poll_status,
|
|
.t1_delay = ni_usb_t1_delay,
|
|
.return_to_local = ni_usb_return_to_local,
|
|
.skip_check_for_command_acceptors = 1
|
|
};
|
|
|
|
// Table with the USB-devices: just now only testing IDs
|
|
static struct usb_device_id ni_usb_driver_device_table[] = {
|
|
{USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_B)},
|
|
{USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_HS)},
|
|
// gpib-usb-hs+ has a second interface for the analyzer, which we ignore
|
|
{USB_DEVICE_INTERFACE_NUMBER(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_HS_PLUS, 0)},
|
|
{USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_KUSB_488A)},
|
|
{USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_MC_USB_488)},
|
|
{} /* Terminating entry */
|
|
};
|
|
MODULE_DEVICE_TABLE(usb, ni_usb_driver_device_table);
|
|
|
|
static int ni_usb_driver_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(interface);
|
|
int i;
|
|
char *path;
|
|
static const int path_length = 1024;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
usb_get_dev(usb_dev);
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) {
|
|
if (!ni_usb_driver_interfaces[i]) {
|
|
ni_usb_driver_interfaces[i] = interface;
|
|
usb_set_intfdata(interface, NULL);
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_NUM_NI_USB_INTERFACES) {
|
|
usb_put_dev(usb_dev);
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
dev_err(&usb_dev->dev, "ni_usb_driver_interfaces[] full\n");
|
|
return -1;
|
|
}
|
|
path = kmalloc(path_length, GFP_KERNEL);
|
|
if (!path) {
|
|
usb_put_dev(usb_dev);
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return -ENOMEM;
|
|
}
|
|
usb_make_path(usb_dev, path, path_length);
|
|
dev_info(&usb_dev->dev, "probe succeeded for path: %s\n", path);
|
|
kfree(path);
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return 0;
|
|
}
|
|
|
|
static void ni_usb_driver_disconnect(struct usb_interface *interface)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(interface);
|
|
int i;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) {
|
|
if (ni_usb_driver_interfaces[i] == interface) {
|
|
struct gpib_board *board = usb_get_intfdata(interface);
|
|
|
|
if (board) {
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
|
|
if (ni_priv) {
|
|
mutex_lock(&ni_priv->bulk_transfer_lock);
|
|
mutex_lock(&ni_priv->control_transfer_lock);
|
|
mutex_lock(&ni_priv->interrupt_transfer_lock);
|
|
ni_usb_cleanup_urbs(ni_priv);
|
|
ni_priv->bus_interface = NULL;
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
mutex_unlock(&ni_priv->control_transfer_lock);
|
|
mutex_unlock(&ni_priv->bulk_transfer_lock);
|
|
}
|
|
}
|
|
ni_usb_driver_interfaces[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_NUM_NI_USB_INTERFACES)
|
|
dev_err(&usb_dev->dev, "unable to find interface bug?\n");
|
|
usb_put_dev(usb_dev);
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
}
|
|
|
|
static int ni_usb_driver_suspend(struct usb_interface *interface, pm_message_t message)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(interface);
|
|
struct gpib_board *board;
|
|
int i, retval;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) {
|
|
if (ni_usb_driver_interfaces[i] == interface) {
|
|
board = usb_get_intfdata(interface);
|
|
if (board)
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_NUM_NI_USB_INTERFACES) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return 0;
|
|
}
|
|
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
|
|
if (ni_priv) {
|
|
ni_usb_set_interrupt_monitor(board, 0);
|
|
retval = ni_usb_shutdown_hardware(ni_priv);
|
|
if (retval) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
if (ni_priv->interrupt_urb) {
|
|
mutex_lock(&ni_priv->interrupt_transfer_lock);
|
|
ni_usb_cleanup_urbs(ni_priv);
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
}
|
|
dev_dbg(&usb_dev->dev,
|
|
"bus %d dev num %d gpib%d, interface %i suspended\n",
|
|
usb_dev->bus->busnum, usb_dev->devnum, board->minor, i);
|
|
}
|
|
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return 0;
|
|
}
|
|
|
|
static int ni_usb_driver_resume(struct usb_interface *interface)
|
|
{
|
|
struct usb_device *usb_dev = interface_to_usbdev(interface);
|
|
|
|
struct gpib_board *board;
|
|
int i, retval;
|
|
|
|
mutex_lock(&ni_usb_hotplug_lock);
|
|
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) {
|
|
if (ni_usb_driver_interfaces[i] == interface) {
|
|
board = usb_get_intfdata(interface);
|
|
if (board)
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_NUM_NI_USB_INTERFACES) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return 0;
|
|
}
|
|
|
|
struct ni_usb_priv *ni_priv = board->private_data;
|
|
|
|
if (ni_priv) {
|
|
if (ni_priv->interrupt_urb) {
|
|
mutex_lock(&ni_priv->interrupt_transfer_lock);
|
|
retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_KERNEL);
|
|
if (retval) {
|
|
dev_err(&usb_dev->dev, "resume failed to resubmit interrupt urb, retval=%i\n",
|
|
retval);
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
mutex_unlock(&ni_priv->interrupt_transfer_lock);
|
|
} else {
|
|
dev_err(&usb_dev->dev, "bug! resume int urb not set up\n");
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (ni_priv->product_id) {
|
|
case USB_DEVICE_ID_NI_USB_B:
|
|
ni_usb_b_read_serial_number(ni_priv);
|
|
break;
|
|
case USB_DEVICE_ID_NI_USB_HS:
|
|
case USB_DEVICE_ID_MC_USB_488:
|
|
case USB_DEVICE_ID_KUSB_488A:
|
|
retval = ni_usb_hs_wait_for_ready(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
break;
|
|
case USB_DEVICE_ID_NI_USB_HS_PLUS:
|
|
retval = ni_usb_hs_wait_for_ready(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
retval = ni_usb_hs_plus_extra_init(ni_priv);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
break;
|
|
default:
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
dev_err(&usb_dev->dev, "\tDriver bug: unknown endpoints for usb device id\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
retval = ni_usb_set_interrupt_monitor(board, 0);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
|
|
retval = ni_usb_init(board);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
retval = ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask);
|
|
if (retval < 0) {
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return retval;
|
|
}
|
|
if (board->master)
|
|
ni_usb_interface_clear(board, 1); // this is a pulsed action
|
|
if (ni_priv->ren_state)
|
|
ni_usb_remote_enable(board, 1);
|
|
|
|
dev_dbg(&usb_dev->dev,
|
|
"bus %d dev num %d gpib%d, interface %i resumed\n",
|
|
usb_dev->bus->busnum, usb_dev->devnum, board->minor, i);
|
|
}
|
|
|
|
mutex_unlock(&ni_usb_hotplug_lock);
|
|
return 0;
|
|
}
|
|
|
|
static struct usb_driver ni_usb_bus_driver = {
|
|
.name = DRV_NAME,
|
|
.probe = ni_usb_driver_probe,
|
|
.disconnect = ni_usb_driver_disconnect,
|
|
.suspend = ni_usb_driver_suspend,
|
|
.resume = ni_usb_driver_resume,
|
|
.id_table = ni_usb_driver_device_table,
|
|
};
|
|
|
|
static int __init ni_usb_init_module(void)
|
|
{
|
|
int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++)
|
|
ni_usb_driver_interfaces[i] = NULL;
|
|
|
|
ret = usb_register(&ni_usb_bus_driver);
|
|
if (ret) {
|
|
pr_err("usb_register failed: error = %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ni_usb_gpib_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit ni_usb_exit_module(void)
|
|
{
|
|
gpib_unregister_driver(&ni_usb_gpib_interface);
|
|
usb_deregister(&ni_usb_bus_driver);
|
|
}
|
|
|
|
module_init(ni_usb_init_module);
|
|
module_exit(ni_usb_exit_module);
|