Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+256
View File
@@ -0,0 +1,256 @@
# SPDX-License-Identifier: GPL-2.0
menuconfig GPIB
tristate "GPIB drivers"
help
Enable support for GPIB cards and dongles. GPIB is the
General Purpose Interface Bus which conforms to the IEEE488
standard.
This set of drivers can be used with the corresponding user
space library that can be found on Sourceforge under linux-gpib.
Select the drivers for your hardware from the list.
if GPIB
config GPIB_COMMON
tristate "GPIB core"
help
Core common driver for all GPIB drivers. It provides the
interface for the userland library
To compile this driver as a module, choose M here: the module will be
called gpib_common
config GPIB_AGILENT_82350B
tristate "Agilent 8235xx PCI(e) adapters"
depends on PCI
select GPIB_COMMON
select GPIB_TMS9914
help
Enable support for HP/Agilent/Keysight boards
82350A
82350B
82351A
To compile this driver as a module, choose M here: the module will be
called agilent_82350b.
config GPIB_AGILENT_82357A
tristate "Agilent 82357a/b USB dongles"
select GPIB_COMMON
depends on USB
help
Enable support for Agilent/Keysight 82357x USB dongles.
To compile this driver as a module, choose M here: the module will be
called agilent_82357a.
config GPIB_CEC_PCI
tristate "CEC PCI board"
depends on PCI
depends on HAS_IOPORT
select GPIB_COMMON
select GPIB_NEC7210
help
Enable support for Capital Equipment Corporation PCI-488
and Keithly KPCI-488 boards.
To compile this driver as a module, choose M here: the module will be
called cec_gpib.
config GPIB_NI_PCI_ISA
tristate "NI PCI/ISA compatible boards"
depends on ISA_BUS || PCI || PCMCIA
depends on HAS_IOPORT
depends on PCMCIA || !PCMCIA
depends on HAS_IOPORT_MAP
select GPIB_COMMON
select GPIB_NEC7210
help
Enable support for National Instruments boards based
on TNT4882 chips:
AT-GPIB (with NAT4882 chip)
AT-GPIB (with NEC7210 chip)
AT-GPIB/TNT
PCI-GPIB
PCIe-GPIB
PCI-GPIB+
PCM-GPIB
PXI-GPIB
PCMCIA-GPIB
and Capital Equipment Corporation CEC-488 board.
To compile this driver as a module, choose M here: the module will be
called tnt4882.
config GPIB_CB7210
tristate "Measurement Computing compatible boards"
depends on HAS_IOPORT
depends on ISA_BUS || PCI || PCMCIA
depends on PCMCIA || !PCMCIA
select GPIB_COMMON
select GPIB_NEC7210
help
Enable support for Measurement Computing (Computer Boards):
CPCI_GPIB, ISA-GPIB, ISA-GPIB/LC, PCI-GPIB/1M, PCI-GPIB/300K and
PCMCIA-GPIB
Quancom PCIGPIB-1 with MC cb7210 chip
To compile this driver as a module, choose M here: the module will be
config GPIB_NI_USB
tristate "NI USB dongles"
select GPIB_COMMON
depends on USB
help
Enable support for National Instruments
GPIB-USB-B
GPIB-USB-HS
GPIB-USB-HS+
Keithly
KUSB-488
KUSB-488A
Measurement Computing (Computer Boards)
USB-488
To compile this driver as a module, choose M here: the module will be
called ni_usb.
config GPIB_FLUKE
tristate "Fluke"
depends on OF
select GPIB_COMMON
select GPIB_NEC7210
depends on HAS_IOMEM
help
GPIB driver for Fluke based cda devices.
To compile this driver as a module, choose M here: the module will be
called fluke_gpib
config GPIB_FMH
tristate "FMH FPGA based devices"
select GPIB_COMMON
select GPIB_NEC7210
depends on !PPC
depends on OF && PCI
help
GPIB driver for fmhess FPGA based devices
To compile this driver as a module, choose M here: the module will be
called fmh_gpib
config GPIB_GPIO
tristate "RPi GPIO bitbang"
depends on ARCH_BCM2835 || COMPILE_TEST
select GPIB_COMMON
help
GPIB bitbang driver Raspberry Pi GPIO adapters
To compile this driver as a module, choose M here: the module will be
called gpib_bitbang
config GPIB_HP82335
tristate "HP82335/HP27209"
depends on ISA_BUS
select GPIB_COMMON
select GPIB_TMS9914
help
GPIB driver for HP82335 and HP27209 boards
To compile this driver as a module, choose M here: the module will be
called hp82335
config GPIB_HP82341
tristate "HP82341x"
select GPIB_COMMON
select GPIB_TMS9914
depends on ISA_BUS || EISA
help
GPIB driver for HP82341 A/B/C/D boards
To compile this driver as a module, choose M here: the module will be
called hp82341
config GPIB_INES
tristate "INES"
depends on PCI || ISA_BUS || PCMCIA
depends on PCMCIA || !PCMCIA
depends on HAS_IOPORT
select GPIB_COMMON
select GPIB_NEC7210
help
GPIB driver for Ines compatible boards
Ines
GPIB-HS-NT
GPIB for Compact PCI
GPIB for PCI
GPIB for PCMCIA
GPIB PC/104
Hameg
HO80-2
Quancom
PCIGPIB-1 based on Ines iGPIB 72010 chip
To compile this driver as a module, choose M here: the module will be
called ines_gpib
called cb7210.
config GPIB_PCMCIA
def_bool y
depends on PCMCIA && (GPIB_NI_PCI_ISA || GPIB_CB7210 || GPIB_INES)
help
Enable PCMCIA/CArdbus support for National Instruments,
measurement computing boards and Ines boards.
config GPIB_LPVO
tristate "LPVO DIY USB GPIB"
select GPIB_COMMON
depends on USB
help
Enable support for LPVO Self-made usb-gpib adapter
To compile this driver as a module, choose M here: the module will be
called lpvo_usb_gpib
config GPIB_PC2
tristate "PC2 PC2a"
depends on ISA_BUS
depends on HAS_IOPORT
select GPIB_COMMON
select GPIB_NEC7210
help
Enable support for pc2 and pc2a compatible adapters
Capital Equipment Corporation PC-488
CONTEC GP-IB(PC)
Hameg HO80
Iotech GP488B
Keithly MBC-488
Measurement Computing ISA-GPIB-PCA2
National Instruments PCII, PCIIa and PCII/IIa
To compile this driver as a module, choose M here: the module will be
called pc2_gpib
config GPIB_TMS9914
tristate
select GPIB_COMMON
help
Enable support for TMS 9914 chip.
To compile this driver as a module, choose M here: the module will be
called tms9914
config GPIB_NEC7210
tristate
select GPIB_COMMON
help
Enable support for NEC 7210 compatible chips.
To compile this driver as a module, choose M here: the module will be
called nec7210
endif # GPIB
+20
View File
@@ -0,0 +1,20 @@
subdir-ccflags-y += -I$(src)/include
obj-$(CONFIG_GPIB_AGILENT_82350B) += agilent_82350b/
obj-$(CONFIG_GPIB_AGILENT_82357A) += agilent_82357a/
obj-$(CONFIG_GPIB_CB7210) += cb7210/
obj-$(CONFIG_GPIB_CEC_PCI) += cec/
obj-$(CONFIG_GPIB_COMMON) += common/
obj-$(CONFIG_GPIB_FLUKE) += eastwood/
obj-$(CONFIG_GPIB_FMH) += fmh_gpib/
obj-$(CONFIG_GPIB_GPIO) += gpio/
obj-$(CONFIG_GPIB_HP82335) += hp_82335/
obj-$(CONFIG_GPIB_HP82341) += hp_82341/
obj-$(CONFIG_GPIB_INES) += ines/
obj-$(CONFIG_GPIB_LPVO) += lpvo_usb_gpib/
obj-$(CONFIG_GPIB_NEC7210) += nec7210/
obj-$(CONFIG_GPIB_NI_USB) += ni_usb/
obj-$(CONFIG_GPIB_PC2) += pc2/
obj-$(CONFIG_GPIB_TMS9914) += tms9914/
obj-$(CONFIG_GPIB_NI_PCI_ISA) += tnt4882/
+10
View File
@@ -0,0 +1,10 @@
TODO:
- checkpatch.pl fixes
These checks should be ignored:
CHECK:ALLOC_SIZEOF_STRUCT: Prefer kmalloc(sizeof(*board->private_data)...) over kmalloc(sizeof(struct xxx_priv)...)
./gpio/gpib_bitbang.c:50: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parenthese
This warning will be addressed later: WARNING:UNDOCUMENTED_DT_STRING: DT compatible string
- resolve XXX notes where possible
- fix FIXME notes
- clean-up commented-out code
- fix typos
@@ -0,0 +1,2 @@
obj-$(CONFIG_GPIB_AGILENT_82350B) += agilent_82350b.o
@@ -0,0 +1,897 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2002, 2004 by Frank Mori Hess *
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#define DRV_NAME KBUILD_MODNAME
#include "agilent_82350b.h"
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/dma.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/wait.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for Agilent 82350b");
static int read_transfer_counter(struct agilent_82350b_priv *a_priv);
static unsigned short read_and_clear_event_status(struct gpib_board *board);
static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count);
static int agilent_82350b_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
static int agilent_82350b_accel_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct agilent_82350b_priv *a_priv = board->private_data;
struct tms9914_priv *tms_priv = &a_priv->tms9914_priv;
int retval = 0;
unsigned short event_status;
int i, num_fifo_bytes;
/* hardware doesn't support checking for end-of-string character when using fifo */
if (tms_priv->eos_flags & REOS)
return tms9914_read(board, tms_priv, buffer, length, end, bytes_read);
clear_bit(DEV_CLEAR_BN, &tms_priv->state);
read_and_clear_event_status(board);
*end = 0;
*bytes_read = 0;
if (length == 0)
return 0;
/* disable fifo for the moment */
writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
/* handle corner case of board not in holdoff and one byte might slip in early */
if (tms_priv->holdoff_active == 0 && length > 1) {
size_t num_bytes;
retval = tms9914_read(board, tms_priv, buffer, 1, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0 || *end)
return retval;
++buffer;
--length;
}
tms9914_set_holdoff_mode(tms_priv, TMS9914_HOLDOFF_EOI);
tms9914_release_holdoff(tms_priv);
i = 0;
num_fifo_bytes = length - 1;
/* disable BI interrupts */
write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0);
while (i < num_fifo_bytes && *end == 0) {
int block_size;
int j;
int count;
block_size = min(num_fifo_bytes - i, agilent_82350b_fifo_size);
set_transfer_counter(a_priv, block_size);
writeb(ENABLE_TI_TO_SRAM | DIRECTION_GPIB_TO_HOST,
a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
if (agilent_82350b_fifo_is_halted(a_priv))
writeb(RESTART_STREAM_BIT, a_priv->gpib_base + STREAM_STATUS_REG);
clear_bit(READ_READY_BN, &tms_priv->state);
retval = wait_event_interruptible(board->wait,
((event_status =
read_and_clear_event_status(board)) &
(TERM_COUNT_STATUS_BIT |
BUFFER_END_STATUS_BIT)) ||
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(TIMO_NUM, &board->status));
if (retval) {
retval = -ERESTARTSYS;
break;
}
count = block_size - read_transfer_counter(a_priv);
for (j = 0; j < count && i < num_fifo_bytes; ++j)
buffer[i++] = readb(a_priv->sram_base + j);
if (event_status & BUFFER_END_STATUS_BIT) {
clear_bit(RECEIVED_END_BN, &tms_priv->state);
tms_priv->holdoff_active = 1;
*end = 1;
}
if (test_bit(TIMO_NUM, &board->status)) {
retval = -ETIMEDOUT;
break;
}
if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) {
retval = -EINTR;
break;
}
}
/* re-enable BI interrupts */
write_byte(tms_priv, tms_priv->imr0_bits, IMR0);
*bytes_read += i;
buffer += i;
length -= i;
writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
if (retval < 0)
return retval;
/* read last bytes if we havn't received an END yet */
if (*end == 0) {
size_t num_bytes;
/* try to make sure we holdoff after last byte read */
retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
return retval;
}
return 0;
}
static int translate_wait_return_value(struct gpib_board *board, int retval)
{
struct agilent_82350b_priv *a_priv = board->private_data;
struct tms9914_priv *tms_priv = &a_priv->tms9914_priv;
if (retval)
return -ERESTARTSYS;
if (test_bit(TIMO_NUM, &board->status))
return -ETIMEDOUT;
if (test_bit(DEV_CLEAR_BN, &tms_priv->state))
return -EINTR;
return 0;
}
static int agilent_82350b_accel_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi,
size_t *bytes_written)
{
struct agilent_82350b_priv *a_priv = board->private_data;
struct tms9914_priv *tms_priv = &a_priv->tms9914_priv;
int i, j;
unsigned short event_status;
int retval = 0;
int fifotransferlength = length;
int block_size = 0;
size_t num_bytes;
*bytes_written = 0;
if (send_eoi)
--fifotransferlength;
clear_bit(DEV_CLEAR_BN, &tms_priv->state);
writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
event_status = read_and_clear_event_status(board);
#ifdef EXPERIMENTAL
/* wait for previous BO to complete if any */
retval = wait_event_interruptible(board->wait,
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(WRITE_READY_BN, &tms_priv->state) ||
test_bit(TIMO_NUM, &board->status));
retval = translate_wait_return_value(board, retval);
if (retval)
return retval;
#endif
if (fifotransferlength > 0) {
retval = agilent_82350b_write(board, buffer, 1, 0, &num_bytes);
*bytes_written += num_bytes;
if (retval < 0)
return retval;
}
write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BOIE, IMR0);
for (i = 1; i < fifotransferlength;) {
clear_bit(WRITE_READY_BN, &tms_priv->state);
block_size = min(fifotransferlength - i, agilent_82350b_fifo_size);
set_transfer_counter(a_priv, block_size);
for (j = 0; j < block_size; ++j, ++i) {
/* load data into board's sram */
writeb(buffer[i], a_priv->sram_base + j);
}
writeb(ENABLE_TI_TO_SRAM, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
if (agilent_82350b_fifo_is_halted(a_priv))
writeb(RESTART_STREAM_BIT, a_priv->gpib_base + STREAM_STATUS_REG);
retval = wait_event_interruptible(board->wait,
((event_status =
read_and_clear_event_status(board)) &
TERM_COUNT_STATUS_BIT) ||
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(TIMO_NUM, &board->status));
writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
num_bytes = block_size - read_transfer_counter(a_priv);
*bytes_written += num_bytes;
retval = translate_wait_return_value(board, retval);
if (retval)
break;
}
write_byte(tms_priv, tms_priv->imr0_bits, IMR0);
if (retval < 0)
return retval;
if (send_eoi) {
retval = agilent_82350b_write(board, buffer + fifotransferlength, 1, send_eoi,
&num_bytes);
*bytes_written += num_bytes;
if (retval < 0)
return retval;
}
return 0;
}
static unsigned short read_and_clear_event_status(struct gpib_board *board)
{
struct agilent_82350b_priv *a_priv = board->private_data;
unsigned long flags;
unsigned short status;
spin_lock_irqsave(&board->spinlock, flags);
status = a_priv->event_status_bits;
a_priv->event_status_bits = 0;
spin_unlock_irqrestore(&board->spinlock, flags);
return status;
}
static irqreturn_t agilent_82350b_interrupt(int irq, void *arg)
{
int tms9914_status1 = 0, tms9914_status2 = 0;
int event_status;
struct gpib_board *board = arg;
struct agilent_82350b_priv *a_priv = board->private_data;
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
spin_lock_irqsave(&board->spinlock, flags);
event_status = readb(a_priv->gpib_base + EVENT_STATUS_REG);
if (event_status & IRQ_STATUS_BIT)
retval = IRQ_HANDLED;
if (event_status & TMS9914_IRQ_STATUS_BIT) {
tms9914_status1 = read_byte(&a_priv->tms9914_priv, ISR0);
tms9914_status2 = read_byte(&a_priv->tms9914_priv, ISR1);
tms9914_interrupt_have_status(board, &a_priv->tms9914_priv, tms9914_status1,
tms9914_status2);
}
/* write-clear status bits */
if (event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT)) {
writeb(event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT),
a_priv->gpib_base + EVENT_STATUS_REG);
a_priv->event_status_bits |= event_status;
wake_up_interruptible(&board->wait);
}
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
static void agilent_82350b_detach(struct gpib_board *board);
static int read_transfer_counter(struct agilent_82350b_priv *a_priv)
{
int lo, mid, value;
lo = readb(a_priv->gpib_base + XFER_COUNT_LO_REG);
mid = readb(a_priv->gpib_base + XFER_COUNT_MID_REG);
value = (lo & 0xff) | ((mid << 8) & 0x7f00);
value = ~(value - 1) & 0x7fff;
return value;
}
static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count)
{
int complement = -count;
writeb(complement & 0xff, a_priv->gpib_base + XFER_COUNT_LO_REG);
writeb((complement >> 8) & 0xff, a_priv->gpib_base + XFER_COUNT_MID_REG);
/* I don't think the hi count reg is even used, but oh well */
writeb((complement >> 16) & 0xf, a_priv->gpib_base + XFER_COUNT_HI_REG);
}
/* wrappers for interface functions */
static int agilent_82350b_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
static int agilent_82350b_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
static int agilent_82350b_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written);
}
static int agilent_82350b_take_control(struct gpib_board *board, int synchronous)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_take_control_workaround(board, &priv->tms9914_priv, synchronous);
}
static int agilent_82350b_go_to_standby(struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
static int agilent_82350b_request_system_control(struct gpib_board *board, int request_control)
{
struct agilent_82350b_priv *a_priv = board->private_data;
if (request_control) {
a_priv->card_mode_bits |= CM_SYSTEM_CONTROLLER_BIT;
if (a_priv->model != MODEL_82350A)
writeb(IC_SYSTEM_CONTROLLER_BIT, a_priv->gpib_base + INTERNAL_CONFIG_REG);
} else {
a_priv->card_mode_bits &= ~CM_SYSTEM_CONTROLLER_BIT;
if (a_priv->model != MODEL_82350A)
writeb(0, a_priv->gpib_base + INTERNAL_CONFIG_REG);
}
writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG);
return tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control);
}
static void agilent_82350b_interface_clear(struct gpib_board *board, int assert)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_interface_clear(board, &priv->tms9914_priv, assert);
}
static void agilent_82350b_remote_enable(struct gpib_board *board, int enable)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
static int agilent_82350b_enable_eos(struct gpib_board *board, u8 eos_byte,
int compare_8_bits)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits);
}
static void agilent_82350b_disable_eos(struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_disable_eos(board, &priv->tms9914_priv);
}
static unsigned int agilent_82350b_update_status(struct gpib_board *board,
unsigned int clear_mask)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_update_status(board, &priv->tms9914_priv, clear_mask);
}
static int agilent_82350b_primary_address(struct gpib_board *board,
unsigned int address)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_primary_address(board, &priv->tms9914_priv, address);
}
static int agilent_82350b_secondary_address(struct gpib_board *board,
unsigned int address, int enable)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
static int agilent_82350b_parallel_poll(struct gpib_board *board, u8 *result)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_parallel_poll(board, &priv->tms9914_priv, result);
}
static void agilent_82350b_parallel_poll_configure(struct gpib_board *board,
u8 config)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config);
}
static void agilent_82350b_parallel_poll_response(struct gpib_board *board, int ist)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
static void agilent_82350b_serial_poll_response(struct gpib_board *board, u8 status)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
static u8 agilent_82350b_serial_poll_status(struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_serial_poll_status(board, &priv->tms9914_priv);
}
static int agilent_82350b_line_status(const struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
return tms9914_line_status(board, &priv->tms9914_priv);
}
static int agilent_82350b_t1_delay(struct gpib_board *board, unsigned int nanosec)
{
struct agilent_82350b_priv *a_priv = board->private_data;
static const int nanosec_per_clock = 30;
unsigned int value;
tms9914_t1_delay(board, &a_priv->tms9914_priv, nanosec);
value = (nanosec + nanosec_per_clock - 1) / nanosec_per_clock;
if (value > 0xff)
value = 0xff;
writeb(value, a_priv->gpib_base + T1_DELAY_REG);
return value * nanosec_per_clock;
}
static void agilent_82350b_return_to_local(struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_return_to_local(board, &priv->tms9914_priv);
}
static int agilent_82350b_allocate_private(struct gpib_board *board)
{
board->private_data = kzalloc_obj(struct agilent_82350b_priv);
if (!board->private_data)
return -ENOMEM;
return 0;
}
static void agilent_82350b_free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
static int init_82350a_hardware(struct gpib_board *board,
const struct gpib_board_config *config)
{
struct agilent_82350b_priv *a_priv = board->private_data;
static const unsigned int firmware_length = 5302;
unsigned int borg_status;
static const unsigned int timeout = 1000;
int i, j;
const char *firmware_data = config->init_data;
const unsigned int plx_cntrl_static_bits = PLX9050_WAITO_NOT_USER0_SELECT_BIT |
PLX9050_USER0_OUTPUT_BIT |
PLX9050_LLOCK_NOT_USER1_SELECT_BIT |
PLX9050_USER1_OUTPUT_BIT |
PLX9050_USER2_OUTPUT_BIT |
PLX9050_USER3_OUTPUT_BIT |
PLX9050_PCI_READ_MODE_BIT |
PLX9050_PCI_WRITE_MODE_BIT |
PLX9050_PCI_RETRY_DELAY_BITS(64) |
PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT;
/* load borg data */
borg_status = readb(a_priv->borg_base);
if ((borg_status & BORG_DONE_BIT))
return 0;
/* need to programme borg */
if (!config->init_data || config->init_data_length != firmware_length) {
dev_err(board->gpib_dev, "the 82350A board requires firmware after powering on.\n");
return -EIO;
}
dev_dbg(board->gpib_dev, "Loading firmware...\n");
/* tickle the borg */
writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT,
a_priv->plx_base + PLX9050_CNTRL_REG);
usleep_range(1000, 2000);
writel(plx_cntrl_static_bits, a_priv->plx_base + PLX9050_CNTRL_REG);
usleep_range(1000, 2000);
writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT,
a_priv->plx_base + PLX9050_CNTRL_REG);
usleep_range(1000, 2000);
for (i = 0; i < config->init_data_length; ++i) {
for (j = 0; j < timeout && (readb(a_priv->borg_base) & BORG_READY_BIT) == 0; ++j) {
if (need_resched())
schedule();
usleep_range(10, 20);
}
if (j == timeout) {
dev_err(board->gpib_dev, "timed out loading firmware.\n");
return -ETIMEDOUT;
}
writeb(firmware_data[i], a_priv->gpib_base + CONFIG_DATA_REG);
}
for (j = 0; j < timeout && (readb(a_priv->borg_base) & BORG_DONE_BIT) == 0; ++j) {
if (need_resched())
schedule();
usleep_range(10, 20);
}
if (j == timeout) {
dev_err(board->gpib_dev, "timed out waiting for firmware load to complete.\n");
return -ETIMEDOUT;
}
dev_dbg(board->gpib_dev, " ...done.\n");
return 0;
}
static int test_sram(struct gpib_board *board)
{
struct agilent_82350b_priv *a_priv = board->private_data;
unsigned int i;
const unsigned int sram_length = pci_resource_len(a_priv->pci_device, SRAM_82350A_REGION);
/* test SRAM */
const unsigned int byte_mask = 0xff;
for (i = 0; i < sram_length; ++i) {
writeb(i & byte_mask, a_priv->sram_base + i);
if (need_resched())
schedule();
}
for (i = 0; i < sram_length; ++i) {
unsigned int read_value = readb(a_priv->sram_base + i);
if ((i & byte_mask) != read_value) {
dev_err(board->gpib_dev, "SRAM test failed at %d wanted %d got %d\n",
i, (i & byte_mask), read_value);
return -EIO;
}
if (need_resched())
schedule();
}
dev_dbg(board->gpib_dev, "SRAM test passed 0x%x bytes checked\n", sram_length);
return 0;
}
static int agilent_82350b_generic_attach(struct gpib_board *board,
const struct gpib_board_config *config,
int use_fifos)
{
struct agilent_82350b_priv *a_priv;
struct tms9914_priv *tms_priv;
int retval;
board->status = 0;
retval = agilent_82350b_allocate_private(board);
if (retval)
return retval;
a_priv = board->private_data;
a_priv->using_fifos = use_fifos;
tms_priv = &a_priv->tms9914_priv;
tms_priv->read_byte = tms9914_iomem_read_byte;
tms_priv->write_byte = tms9914_iomem_write_byte;
tms_priv->offset = 1;
/* find board */
a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT,
PCI_DEVICE_ID_82350B, NULL);
if (a_priv->pci_device) {
a_priv->model = MODEL_82350B;
dev_dbg(board->gpib_dev, "Agilent 82350B board found\n");
} else {
a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT,
PCI_DEVICE_ID_82351A, NULL);
if (a_priv->pci_device) {
a_priv->model = MODEL_82351A;
dev_dbg(board->gpib_dev, "Agilent 82351B board found\n");
} else {
a_priv->pci_device = gpib_pci_get_subsys(config, PCI_VENDOR_ID_PLX,
PCI_DEVICE_ID_PLX_9050,
PCI_VENDOR_ID_HP,
PCI_SUBDEVICE_ID_82350A,
a_priv->pci_device);
if (a_priv->pci_device) {
a_priv->model = MODEL_82350A;
dev_dbg(board->gpib_dev, "HP/Agilent 82350A board found\n");
} else {
dev_err(board->gpib_dev, "no 82350/82351 board found\n");
return -ENODEV;
}
}
}
if (pci_enable_device(a_priv->pci_device)) {
dev_err(board->gpib_dev, "error enabling pci device\n");
return -EIO;
}
if (pci_request_regions(a_priv->pci_device, DRV_NAME))
return -ENOMEM;
switch (a_priv->model) {
case MODEL_82350A:
a_priv->plx_base = ioremap(pci_resource_start(a_priv->pci_device, PLX_MEM_REGION),
pci_resource_len(a_priv->pci_device, PLX_MEM_REGION));
dev_dbg(board->gpib_dev, "plx base address remapped to 0x%p\n", a_priv->plx_base);
a_priv->gpib_base = ioremap(pci_resource_start(a_priv->pci_device,
GPIB_82350A_REGION),
pci_resource_len(a_priv->pci_device,
GPIB_82350A_REGION));
dev_dbg(board->gpib_dev, "chip base address remapped to 0x%p\n", a_priv->gpib_base);
tms_priv->mmiobase = a_priv->gpib_base + TMS9914_BASE_REG;
a_priv->sram_base = ioremap(pci_resource_start(a_priv->pci_device,
SRAM_82350A_REGION),
pci_resource_len(a_priv->pci_device,
SRAM_82350A_REGION));
dev_dbg(board->gpib_dev, "sram base address remapped to 0x%p\n", a_priv->sram_base);
a_priv->borg_base = ioremap(pci_resource_start(a_priv->pci_device,
BORG_82350A_REGION),
pci_resource_len(a_priv->pci_device,
BORG_82350A_REGION));
dev_dbg(board->gpib_dev, "borg base address remapped to 0x%p\n", a_priv->borg_base);
retval = init_82350a_hardware(board, config);
if (retval < 0)
return retval;
break;
case MODEL_82350B:
case MODEL_82351A:
a_priv->gpib_base = ioremap(pci_resource_start(a_priv->pci_device, GPIB_REGION),
pci_resource_len(a_priv->pci_device, GPIB_REGION));
dev_dbg(board->gpib_dev, "chip base address remapped to 0x%p\n", a_priv->gpib_base);
tms_priv->mmiobase = a_priv->gpib_base + TMS9914_BASE_REG;
a_priv->sram_base = ioremap(pci_resource_start(a_priv->pci_device, SRAM_REGION),
pci_resource_len(a_priv->pci_device, SRAM_REGION));
dev_dbg(board->gpib_dev, "sram base address remapped to 0x%p\n", a_priv->sram_base);
a_priv->misc_base = ioremap(pci_resource_start(a_priv->pci_device, MISC_REGION),
pci_resource_len(a_priv->pci_device, MISC_REGION));
dev_dbg(board->gpib_dev, "misc base address remapped to 0x%p\n", a_priv->misc_base);
break;
default:
dev_err(board->gpib_dev, "invalid board\n");
return -ENODEV;
}
retval = test_sram(board);
if (retval < 0)
return retval;
if (request_irq(a_priv->pci_device->irq, agilent_82350b_interrupt,
IRQF_SHARED, DRV_NAME, board)) {
dev_err(board->gpib_dev, "failed to obtain irq %d\n", a_priv->pci_device->irq);
return -EIO;
}
a_priv->irq = a_priv->pci_device->irq;
dev_dbg(board->gpib_dev, " IRQ %d\n", a_priv->irq);
writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
a_priv->card_mode_bits = ENABLE_PCI_IRQ_BIT;
writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG);
if (a_priv->model == MODEL_82350A) {
/* enable PCI interrupts for 82350a */
writel(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR2_POLARITY_BIT |
PLX9050_PCI_INTR_EN_BIT,
a_priv->plx_base + PLX9050_INTCSR_REG);
}
if (use_fifos) {
writeb(ENABLE_BUFFER_END_EVENTS_BIT | ENABLE_TERM_COUNT_EVENTS_BIT,
a_priv->gpib_base + EVENT_ENABLE_REG);
writeb(ENABLE_TERM_COUNT_INTERRUPT_BIT | ENABLE_BUFFER_END_INTERRUPT_BIT |
ENABLE_TMS9914_INTERRUPTS_BIT, a_priv->gpib_base + INTERRUPT_ENABLE_REG);
/* write-clear event status bits */
writeb(BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT,
a_priv->gpib_base + EVENT_STATUS_REG);
} else {
writeb(0, a_priv->gpib_base + EVENT_ENABLE_REG);
writeb(ENABLE_TMS9914_INTERRUPTS_BIT,
a_priv->gpib_base + INTERRUPT_ENABLE_REG);
}
board->t1_nano_sec = agilent_82350b_t1_delay(board, 2000);
tms9914_board_reset(tms_priv);
tms9914_online(board, tms_priv);
return 0;
}
static int agilent_82350b_unaccel_attach(struct gpib_board *board,
const struct gpib_board_config *config)
{
return agilent_82350b_generic_attach(board, config, 0);
}
static int agilent_82350b_accel_attach(struct gpib_board *board,
const struct gpib_board_config *config)
{
return agilent_82350b_generic_attach(board, config, 1);
}
static void agilent_82350b_detach(struct gpib_board *board)
{
struct agilent_82350b_priv *a_priv = board->private_data;
struct tms9914_priv *tms_priv;
if (a_priv) {
if (a_priv->plx_base) /* disable interrupts */
writel(0, a_priv->plx_base + PLX9050_INTCSR_REG);
tms_priv = &a_priv->tms9914_priv;
if (a_priv->irq)
free_irq(a_priv->irq, board);
if (a_priv->gpib_base) {
tms9914_board_reset(tms_priv);
if (a_priv->misc_base)
iounmap(a_priv->misc_base);
if (a_priv->borg_base)
iounmap(a_priv->borg_base);
if (a_priv->sram_base)
iounmap(a_priv->sram_base);
if (a_priv->gpib_base)
iounmap(a_priv->gpib_base);
if (a_priv->plx_base)
iounmap(a_priv->plx_base);
pci_release_regions(a_priv->pci_device);
}
if (a_priv->pci_device)
pci_dev_put(a_priv->pci_device);
}
agilent_82350b_free_private(board);
}
static struct gpib_interface agilent_82350b_unaccel_interface = {
.name = "agilent_82350b_unaccel",
.attach = agilent_82350b_unaccel_attach,
.detach = agilent_82350b_detach,
.read = agilent_82350b_read,
.write = agilent_82350b_write,
.command = agilent_82350b_command,
.request_system_control = agilent_82350b_request_system_control,
.take_control = agilent_82350b_take_control,
.go_to_standby = agilent_82350b_go_to_standby,
.interface_clear = agilent_82350b_interface_clear,
.remote_enable = agilent_82350b_remote_enable,
.enable_eos = agilent_82350b_enable_eos,
.disable_eos = agilent_82350b_disable_eos,
.parallel_poll = agilent_82350b_parallel_poll,
.parallel_poll_configure = agilent_82350b_parallel_poll_configure,
.parallel_poll_response = agilent_82350b_parallel_poll_response,
.local_parallel_poll_mode = NULL, /* XXX */
.line_status = agilent_82350b_line_status,
.update_status = agilent_82350b_update_status,
.primary_address = agilent_82350b_primary_address,
.secondary_address = agilent_82350b_secondary_address,
.serial_poll_response = agilent_82350b_serial_poll_response,
.serial_poll_status = agilent_82350b_serial_poll_status,
.t1_delay = agilent_82350b_t1_delay,
.return_to_local = agilent_82350b_return_to_local,
};
static struct gpib_interface agilent_82350b_interface = {
.name = "agilent_82350b",
.attach = agilent_82350b_accel_attach,
.detach = agilent_82350b_detach,
.read = agilent_82350b_accel_read,
.write = agilent_82350b_accel_write,
.command = agilent_82350b_command,
.request_system_control = agilent_82350b_request_system_control,
.take_control = agilent_82350b_take_control,
.go_to_standby = agilent_82350b_go_to_standby,
.interface_clear = agilent_82350b_interface_clear,
.remote_enable = agilent_82350b_remote_enable,
.enable_eos = agilent_82350b_enable_eos,
.disable_eos = agilent_82350b_disable_eos,
.parallel_poll = agilent_82350b_parallel_poll,
.parallel_poll_configure = agilent_82350b_parallel_poll_configure,
.parallel_poll_response = agilent_82350b_parallel_poll_response,
.local_parallel_poll_mode = NULL, /* XXX */
.line_status = agilent_82350b_line_status,
.update_status = agilent_82350b_update_status,
.primary_address = agilent_82350b_primary_address,
.secondary_address = agilent_82350b_secondary_address,
.serial_poll_response = agilent_82350b_serial_poll_response,
.serial_poll_status = agilent_82350b_serial_poll_status,
.t1_delay = agilent_82350b_t1_delay,
.return_to_local = agilent_82350b_return_to_local,
};
static int agilent_82350b_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
return 0;
}
static const struct pci_device_id agilent_82350b_pci_table[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_HP,
PCI_SUBDEVICE_ID_82350A, 0, 0, 0 },
{ PCI_VENDOR_ID_AGILENT, PCI_DEVICE_ID_82350B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_AGILENT, PCI_DEVICE_ID_82351A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, agilent_82350b_pci_table);
static struct pci_driver agilent_82350b_pci_driver = {
.name = DRV_NAME,
.id_table = agilent_82350b_pci_table,
.probe = &agilent_82350b_pci_probe
};
static int __init agilent_82350b_init_module(void)
{
int result;
result = pci_register_driver(&agilent_82350b_pci_driver);
if (result) {
pr_err("pci_register_driver failed: error = %d\n", result);
return result;
}
result = gpib_register_driver(&agilent_82350b_unaccel_interface, THIS_MODULE);
if (result) {
pr_err("gpib_register_driver failed: error = %d\n", result);
goto err_unaccel;
}
result = gpib_register_driver(&agilent_82350b_interface, THIS_MODULE);
if (result) {
pr_err("gpib_register_driver failed: error = %d\n", result);
goto err_interface;
}
return 0;
err_interface:
gpib_unregister_driver(&agilent_82350b_unaccel_interface);
err_unaccel:
pci_unregister_driver(&agilent_82350b_pci_driver);
return result;
}
static void __exit agilent_82350b_exit_module(void)
{
gpib_unregister_driver(&agilent_82350b_interface);
gpib_unregister_driver(&agilent_82350b_unaccel_interface);
pci_unregister_driver(&agilent_82350b_pci_driver);
}
module_init(agilent_82350b_init_module);
module_exit(agilent_82350b_exit_module);
@@ -0,0 +1,157 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002, 2004 by Frank Mori Hess *
***************************************************************************/
#include "gpibP.h"
#include "plx9050.h"
#include "tms9914.h"
enum pci_vendor_ids {
PCI_VENDOR_ID_AGILENT = 0x15bc,
};
enum pci_device_ids {
PCI_DEVICE_ID_82350B = 0x0b01,
PCI_DEVICE_ID_82351A = 0x1218
};
enum pci_subdevice_ids {
PCI_SUBDEVICE_ID_82350A = 0x10b0,
};
enum pci_regions_82350a {
PLX_MEM_REGION = 0,
PLX_IO_REGION = 1,
GPIB_82350A_REGION = 2,
SRAM_82350A_REGION = 3,
BORG_82350A_REGION = 4
};
enum pci_regions_82350b {
GPIB_REGION = 0,
SRAM_REGION = 1,
MISC_REGION = 2,
};
enum board_model {
MODEL_82350A,
MODEL_82350B,
MODEL_82351A
};
/* struct which defines private_data for board */
struct agilent_82350b_priv {
struct tms9914_priv tms9914_priv;
struct pci_dev *pci_device;
void __iomem *plx_base; /* 82350a only */
void __iomem *gpib_base;
void __iomem *sram_base;
void __iomem *misc_base;
void __iomem *borg_base;
int irq;
unsigned short card_mode_bits;
unsigned short event_status_bits;
enum board_model model;
bool using_fifos;
};
/* registers */
enum agilent_82350b_gpib_registers
{
CARD_MODE_REG = 0x1,
CONFIG_DATA_REG = 0x2, /* 82350A specific */
INTERRUPT_ENABLE_REG = 0x3,
EVENT_STATUS_REG = 0x4,
EVENT_ENABLE_REG = 0x5,
STREAM_STATUS_REG = 0x7,
DEBUG_RAM0_REG = 0x8,
DEBUG_RAM1_REG = 0x9,
DEBUG_RAM2_REG = 0xa,
DEBUG_RAM3_REG = 0xb,
XFER_COUNT_LO_REG = 0xc,
XFER_COUNT_MID_REG = 0xd,
XFER_COUNT_HI_REG = 0xe,
TMS9914_BASE_REG = 0x10,
INTERNAL_CONFIG_REG = 0x18,
IMR0_READ_REG = 0x19, /* read */
T1_DELAY_REG = 0x19, /* write */
IMR1_READ_REG = 0x1a,
ADR_READ_REG = 0x1b,
SPMR_READ_REG = 0x1c,
PPR_READ_REG = 0x1d,
CDOR_READ_REG = 0x1e,
SRAM_ACCESS_CONTROL_REG = 0x1f,
};
enum card_mode_bits
{
ACTIVE_CONTROLLER_BIT = 0x2, /* read-only */
CM_SYSTEM_CONTROLLER_BIT = 0x8,
ENABLE_BUS_MONITOR_BIT = 0x10,
ENABLE_PCI_IRQ_BIT = 0x20,
};
enum interrupt_enable_bits
{
ENABLE_TMS9914_INTERRUPTS_BIT = 0x1,
ENABLE_BUFFER_END_INTERRUPT_BIT = 0x10,
ENABLE_TERM_COUNT_INTERRUPT_BIT = 0x20,
};
enum event_enable_bits
{
ENABLE_BUFFER_END_EVENTS_BIT = 0x10,
ENABLE_TERM_COUNT_EVENTS_BIT = 0x20,
};
enum event_status_bits
{
TMS9914_IRQ_STATUS_BIT = 0x1,
IRQ_STATUS_BIT = 0x2,
BUFFER_END_STATUS_BIT = 0x10, /* write-clear */
TERM_COUNT_STATUS_BIT = 0x20, /* write-clear */
};
enum stream_status_bits
{
HALTED_STATUS_BIT = 0x1, /* read */
RESTART_STREAM_BIT = 0x1, /* write */
};
enum internal_config_bits
{
IC_SYSTEM_CONTROLLER_BIT = 0x80,
};
enum sram_access_control_bits
{
DIRECTION_GPIB_TO_HOST = 0x20, /* transfer direction */
ENABLE_TI_TO_SRAM = 0x40, /* enable fifo */
ENABLE_FAST_TALKER = 0x80 /* added for 82350A (not used) */
};
enum borg_bits
{
BORG_READY_BIT = 0x40,
BORG_DONE_BIT = 0x80
};
static const int agilent_82350b_fifo_size = 0x8000;
static inline int agilent_82350b_fifo_is_halted(struct agilent_82350b_priv *a_priv)
{
return readb(a_priv->gpib_base + STREAM_STATUS_REG) & HALTED_STATUS_BIT;
}
@@ -0,0 +1,4 @@
obj-$(CONFIG_GPIB_AGILENT_82357A) += agilent_82357a.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,182 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2004 by Frank Mori Hess *
***************************************************************************/
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/usb.h>
#include <linux/timer.h>
#include <linux/compiler_attributes.h>
#include "gpibP.h"
#include "tms9914.h"
enum usb_vendor_ids {
USB_VENDOR_ID_AGILENT = 0x0957
};
enum usb_device_ids {
USB_DEVICE_ID_AGILENT_82357A = 0x0107,
USB_DEVICE_ID_AGILENT_82357A_PREINIT = 0x0007, // device id before firmware is loaded
USB_DEVICE_ID_AGILENT_82357B = 0x0718, // device id before firmware is loaded
USB_DEVICE_ID_AGILENT_82357B_PREINIT = 0x0518, // device id before firmware is loaded
};
enum endpoint_addresses {
AGILENT_82357_CONTROL_ENDPOINT = 0x0,
AGILENT_82357_BULK_IN_ENDPOINT = 0x2,
AGILENT_82357A_BULK_OUT_ENDPOINT = 0x4,
AGILENT_82357A_INTERRUPT_IN_ENDPOINT = 0x6,
AGILENT_82357B_BULK_OUT_ENDPOINT = 0x6,
AGILENT_82357B_INTERRUPT_IN_ENDPOINT = 0x8,
};
enum bulk_commands {
DATA_PIPE_CMD_WRITE = 0x1,
DATA_PIPE_CMD_READ = 0x3,
DATA_PIPE_CMD_WR_REGS = 0x4,
DATA_PIPE_CMD_RD_REGS = 0x5
};
enum agilent_82357a_read_flags {
ARF_END_ON_EOI = 0x1,
ARF_NO_ADDRESS = 0x2,
ARF_END_ON_EOS_CHAR = 0x4,
ARF_SPOLL = 0x8
};
enum agilent_82357a_trailing_read_flags {
ATRF_EOI = 0x1,
ATRF_ATN = 0x2,
ATRF_IFC = 0x4,
ATRF_EOS = 0x8,
ATRF_ABORT = 0x10,
ATRF_COUNT = 0x20,
ATRF_DEAD_BUS = 0x40,
ATRF_UNADDRESSED = 0x80
};
enum agilent_82357a_write_flags {
AWF_SEND_EOI = 0x1,
AWF_NO_FAST_TALKER_FIRST_BYTE = 0x2,
AWF_NO_FAST_TALKER = 0x4,
AWF_NO_ADDRESS = 0x8,
AWF_ATN = 0x10,
AWF_SEPARATE_HEADER = 0x80
};
enum agilent_82357a_interrupt_flag_bit_numbers {
AIF_SRQ_BN = 0,
AIF_WRITE_COMPLETE_BN = 1,
AIF_READ_COMPLETE_BN = 2,
};
enum agilent_82357_error_codes {
UGP_SUCCESS = 0,
UGP_ERR_INVALID_CMD = 1,
UGP_ERR_INVALID_PARAM = 2,
UGP_ERR_INVALID_REG = 3,
UGP_ERR_GPIB_READ = 4,
UGP_ERR_GPIB_WRITE = 5,
UGP_ERR_FLUSHING = 6,
UGP_ERR_FLUSHING_ALREADY = 7,
UGP_ERR_UNSUPPORTED = 8,
UGP_ERR_OTHER = 9
};
enum agilent_82357_control_values {
XFER_ABORT = 0xa0,
XFER_STATUS = 0xb0,
};
enum xfer_status_bits {
XS_COMPLETED = 0x1,
XS_READ = 0x2,
};
enum xfer_status_completion_bits {
XSC_EOI = 0x1,
XSC_ATN = 0x2,
XSC_IFC = 0x4,
XSC_EOS = 0x8,
XSC_ABORT = 0x10,
XSC_COUNT = 0x20,
XSC_DEAD_BUS = 0x40,
XSC_BUS_NOT_ADDRESSED = 0x80
};
enum xfer_abort_type {
XA_FLUSH = 0x1
};
#define STATUS_DATA_LEN 8
#define INTERRUPT_BUF_LEN 8
struct agilent_82357a_urb_ctx {
struct completion complete;
unsigned timed_out : 1;
};
// struct which defines local data for each 82357 device
struct agilent_82357a_priv {
struct usb_interface *bus_interface;
unsigned short eos_char;
unsigned short eos_mode;
unsigned short hw_control_bits;
unsigned long interrupt_flags;
struct urb *bulk_urb;
struct urb *interrupt_urb;
u8 *interrupt_buffer;
struct mutex bulk_transfer_lock; // bulk transfer lock
struct mutex bulk_alloc_lock; // bulk transfer allocation lock
struct mutex interrupt_alloc_lock; // interrupt allocation lock
struct mutex control_alloc_lock; // control message allocation lock
struct timer_list bulk_timer;
struct agilent_82357a_urb_ctx context;
unsigned int bulk_out_endpoint;
unsigned int interrupt_in_endpoint;
unsigned is_cic : 1;
unsigned ren_state : 1;
};
struct agilent_82357a_register_pairlet {
short address;
unsigned short value;
};
enum firmware_registers {
HW_CONTROL = 0xa,
LED_CONTROL = 0xb,
RESET_TO_POWERUP = 0xc,
PROTOCOL_CONTROL = 0xd,
FAST_TALKER_T1 = 0xe
};
enum hardware_control_bits {
NOT_TI_RESET = 0x1,
SYSTEM_CONTROLLER = 0x2,
NOT_PARALLEL_POLL = 0x4,
OSCILLATOR_5V_ON = 0x8,
OUTPUT_5V_ON = 0x20,
CPLD_3V_ON = 0x80,
};
enum led_control_bits {
FIRMWARE_LED_CONTROL = 0x1,
FAIL_LED_ON = 0x20,
READY_LED_ON = 0x40,
ACCESS_LED_ON = 0x80
};
enum reset_to_powerup_bits {
RESET_SPACEBALL = 0x1, // wait 2 millisec after sending
};
enum protocol_control_bits {
WRITE_COMPLETE_INTERRUPT_EN = 0x1,
};
static const int agilent_82357a_control_request = 0x4;
+3
View File
@@ -0,0 +1,3 @@
obj-$(CONFIG_GPIB_CB7210) += cb7210.o
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#include "nec7210.h"
#include "gpibP.h"
#include "amccs5933.h"
#include <linux/delay.h>
#include <linux/interrupt.h>
enum {
PCI_DEVICE_ID_CBOARDS_PCI_GPIB = 0x6,
PCI_DEVICE_ID_CBOARDS_CPCI_GPIB = 0xe,
};
enum pci_chip {
PCI_CHIP_NONE = 0,
PCI_CHIP_AMCC_S5933,
PCI_CHIP_QUANCOM
};
// struct which defines private_data for cb7210 boards
struct cb7210_priv {
struct nec7210_priv nec7210_priv;
struct pci_dev *pci_device;
// base address of amccs5933 pci chip
unsigned long amcc_iobase;
unsigned long fifo_iobase;
unsigned int irq;
enum pci_chip pci_chip;
u8 hs_mode_bits;
unsigned out_fifo_half_empty : 1;
unsigned in_fifo_half_full : 1;
};
// pci-gpib register offset
static const int cb7210_reg_offset = 1;
// uses 10 ioports
static const int cb7210_iosize = 10;
// fifo size in bytes
static const int cb7210_fifo_size = 2048;
static const int cb7210_fifo_width = 2;
// cb7210 specific registers and bits
enum cb7210_regs {
BUS_STATUS = 0x7,
};
enum cb7210_page_in {
BUS_STATUS_PAGE = 1,
};
enum hs_regs {
// write registers
HS_MODE = 0x8, /* HS_MODE register */
HS_INT_LEVEL = 0x9, /* HS_INT_LEVEL register */
// read registers
HS_STATUS = 0x8, /* HS_STATUS register */
};
static inline u32 nec7210_iobase(const struct cb7210_priv *cb_priv)
{
return cb_priv->nec7210_priv.iobase;
}
static inline int cb7210_page_in_bits(unsigned int page)
{
return 0x50 | (page & 0xf);
}
static inline u8 cb7210_paged_read_byte(struct cb7210_priv *cb_priv,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
u8 retval;
unsigned long flags;
spin_lock_irqsave(&nec_priv->register_page_lock, flags);
outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset);
udelay(1);
retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
return retval;
}
// don't use for register_num < 8, since it doesn't lock
static inline u8 cb7210_read_byte(const struct cb7210_priv *cb_priv,
enum hs_regs register_num)
{
const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
u8 retval;
retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
return retval;
}
static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, u8 data,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
unsigned long flags;
spin_lock_irqsave(&nec_priv->register_page_lock, flags);
outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset);
udelay(1);
outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
}
// don't use for register_num < 8, since it doesn't lock
static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, u8 data,
enum hs_regs register_num)
{
const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset);
}
enum bus_status_bits {
BSR_ATN_BIT = 0x1,
BSR_EOI_BIT = 0x2,
BSR_SRQ_BIT = 0x4,
BSR_IFC_BIT = 0x8,
BSR_REN_BIT = 0x10,
BSR_DAV_BIT = 0x20,
BSR_NRFD_BIT = 0x40,
BSR_NDAC_BIT = 0x80,
};
/* CBI 488.2 HS control */
/*
* when both bit 0 and 1 are set, it
* 1 clears the transmit state machine to an initial condition
* 2 clears any residual interrupts left latched on cbi488.2
* 3 resets all control bits in HS_MODE to zero
* 4 enables TX empty interrupts
* when both bit 0 and 1 are zero, then the high speed mode is disabled
*/
enum hs_mode_bits {
HS_ENABLE_MASK = 0x3,
HS_TX_ENABLE = (1 << 0),
HS_RX_ENABLE = (1 << 1),
HS_HF_INT_EN = (1 << 3),
HS_CLR_SRQ_INT = (1 << 4),
HS_CLR_EOI_EMPTY_INT = (1 << 5),
HS_CLR_HF_INT = (1 << 6),
HS_SYS_CONTROL = (1 << 7),
};
/* CBI 488.2 status */
enum hs_status_bits {
HS_FIFO_FULL = (1 << 0),
HS_HALF_FULL = (1 << 1),
HS_SRQ_INT = (1 << 2),
HS_EOI_INT = (1 << 3),
HS_TX_MSB_NOT_EMPTY = (1 << 4),
HS_RX_MSB_NOT_EMPTY = (1 << 5),
HS_TX_LSB_NOT_EMPTY = (1 << 6),
HS_RX_LSB_NOT_EMPTY = (1 << 7),
};
/* CBI488.2 hs_int_level register */
enum hs_int_level_bits {
HS_RESET7210 = (1 << 7),
};
static inline unsigned int irq_bits(unsigned int irq)
{
switch (irq) {
case 2:
case 3:
case 4:
case 5:
return irq - 1;
case 7:
return 0x5;
case 10:
return 0x6;
case 11:
return 0x7;
default:
return 0;
}
}
enum cb7210_aux_cmds {
/*
* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
* (and keep asserted) local rtl message. This is used in conjunction
* with the (stupid) cb7210 implementation
* of the normal nec7210 AUX_RTL aux command, which
* causes the rtl message to toggle between on and off.
*/
AUX_RTL2 = 0xd,
AUX_LO_SPEED = 0x40,
AUX_HI_SPEED = 0x41,
};
+3
View File
@@ -0,0 +1,3 @@
obj-$(CONFIG_GPIB_CEC_PCI) += cec_gpib.o
+20
View File
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#include "nec7210.h"
#include "gpibP.h"
#include "plx9050.h"
struct cec_priv {
struct nec7210_priv nec7210_priv;
struct pci_dev *pci_device;
// base address for plx9052 pci chip
unsigned long plx_iobase;
unsigned int irq;
};
// offset between consecutive nec7210 registers
static const int cec_reg_offset = 1;
+394
View File
@@ -0,0 +1,394 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#define DRV_NAME KBUILD_MODNAME
#include "cec.h"
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <asm/dma.h>
#include <linux/module.h>
#include <linux/slab.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for CEC PCI and PCMCIA boards");
/*
* GPIB interrupt service routines
*/
static irqreturn_t cec_interrupt(int irq, void *arg)
{
struct gpib_board *board = arg;
struct cec_priv *priv = board->private_data;
unsigned long flags;
irqreturn_t retval;
spin_lock_irqsave(&board->spinlock, flags);
retval = nec7210_interrupt(board, &priv->nec7210_priv);
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
#define CEC_VENDOR_ID 0x12fc
#define CEC_DEV_ID 0x5cec
#define CEC_SUBID 0x9050
static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void cec_pci_detach(struct gpib_board *board);
// wrappers for interface functions
static int cec_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct cec_priv *priv = board->private_data;
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
static int cec_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct cec_priv *priv = board->private_data;
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
static int cec_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct cec_priv *priv = board->private_data;
return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written);
}
static int cec_take_control(struct gpib_board *board, int synchronous)
{
struct cec_priv *priv = board->private_data;
return nec7210_take_control(board, &priv->nec7210_priv, synchronous);
}
static int cec_go_to_standby(struct gpib_board *board)
{
struct cec_priv *priv = board->private_data;
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
static int cec_request_system_control(struct gpib_board *board, int request_control)
{
struct cec_priv *priv = board->private_data;
return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
}
static void cec_interface_clear(struct gpib_board *board, int assert)
{
struct cec_priv *priv = board->private_data;
nec7210_interface_clear(board, &priv->nec7210_priv, assert);
}
static void cec_remote_enable(struct gpib_board *board, int enable)
{
struct cec_priv *priv = board->private_data;
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
static int cec_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct cec_priv *priv = board->private_data;
return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits);
}
static void cec_disable_eos(struct gpib_board *board)
{
struct cec_priv *priv = board->private_data;
nec7210_disable_eos(board, &priv->nec7210_priv);
}
static unsigned int cec_update_status(struct gpib_board *board, unsigned int clear_mask)
{
struct cec_priv *priv = board->private_data;
return nec7210_update_status(board, &priv->nec7210_priv, clear_mask);
}
static int cec_primary_address(struct gpib_board *board, unsigned int address)
{
struct cec_priv *priv = board->private_data;
return nec7210_primary_address(board, &priv->nec7210_priv, address);
}
static int cec_secondary_address(struct gpib_board *board, unsigned int address, int enable)
{
struct cec_priv *priv = board->private_data;
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
static int cec_parallel_poll(struct gpib_board *board, u8 *result)
{
struct cec_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
static void cec_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct cec_priv *priv = board->private_data;
nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config);
}
static void cec_parallel_poll_response(struct gpib_board *board, int ist)
{
struct cec_priv *priv = board->private_data;
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
static void cec_serial_poll_response(struct gpib_board *board, u8 status)
{
struct cec_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
static u8 cec_serial_poll_status(struct gpib_board *board)
{
struct cec_priv *priv = board->private_data;
return nec7210_serial_poll_status(board, &priv->nec7210_priv);
}
static int cec_t1_delay(struct gpib_board *board, unsigned int nano_sec)
{
struct cec_priv *priv = board->private_data;
return nec7210_t1_delay(board, &priv->nec7210_priv, nano_sec);
}
static void cec_return_to_local(struct gpib_board *board)
{
struct cec_priv *priv = board->private_data;
nec7210_return_to_local(board, &priv->nec7210_priv);
}
static struct gpib_interface cec_pci_interface = {
.name = "cec_pci",
.attach = cec_pci_attach,
.detach = cec_pci_detach,
.read = cec_read,
.write = cec_write,
.command = cec_command,
.take_control = cec_take_control,
.go_to_standby = cec_go_to_standby,
.request_system_control = cec_request_system_control,
.interface_clear = cec_interface_clear,
.remote_enable = cec_remote_enable,
.enable_eos = cec_enable_eos,
.disable_eos = cec_disable_eos,
.parallel_poll = cec_parallel_poll,
.parallel_poll_configure = cec_parallel_poll_configure,
.parallel_poll_response = cec_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = NULL, // XXX
.update_status = cec_update_status,
.primary_address = cec_primary_address,
.secondary_address = cec_secondary_address,
.serial_poll_response = cec_serial_poll_response,
.serial_poll_status = cec_serial_poll_status,
.t1_delay = cec_t1_delay,
.return_to_local = cec_return_to_local,
};
static int cec_allocate_private(struct gpib_board *board)
{
struct cec_priv *priv;
board->private_data = kzalloc_obj(struct cec_priv);
if (!board->private_data)
return -ENOMEM;
priv = board->private_data;
init_nec7210_private(&priv->nec7210_priv);
return 0;
}
static void cec_free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
static int cec_generic_attach(struct gpib_board *board)
{
struct cec_priv *cec_priv;
struct nec7210_priv *nec_priv;
int retval;
board->status = 0;
retval = cec_allocate_private(board);
if (retval)
return retval;
cec_priv = board->private_data;
nec_priv = &cec_priv->nec7210_priv;
nec_priv->read_byte = nec7210_ioport_read_byte;
nec_priv->write_byte = nec7210_ioport_write_byte;
nec_priv->offset = cec_reg_offset;
nec_priv->type = NEC7210; // guess
return 0;
}
static void cec_init(struct cec_priv *cec_priv, const struct gpib_board *board)
{
struct nec7210_priv *nec_priv = &cec_priv->nec7210_priv;
nec7210_board_reset(nec_priv, board);
/* set internal counter register for 8 MHz input clock */
write_byte(nec_priv, ICR | 8, AUXMR);
nec7210_board_online(nec_priv, board);
}
static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct cec_priv *cec_priv;
struct nec7210_priv *nec_priv;
int isr_flags = 0;
int retval;
retval = cec_generic_attach(board);
if (retval)
return retval;
cec_priv = board->private_data;
nec_priv = &cec_priv->nec7210_priv;
// find board
cec_priv->pci_device = NULL;
while ((cec_priv->pci_device =
gpib_pci_get_device(config, CEC_VENDOR_ID,
CEC_DEV_ID, cec_priv->pci_device))) {
// check for board with plx9050 controller
if (cec_priv->pci_device->subsystem_device == CEC_SUBID)
break;
}
if (!cec_priv->pci_device) {
dev_err(board->gpib_dev, "no cec PCI board found\n");
return -ENODEV;
}
if (pci_enable_device(cec_priv->pci_device)) {
dev_err(board->gpib_dev, "error enabling pci device\n");
return -EIO;
}
if (pci_request_regions(cec_priv->pci_device, "cec-gpib"))
return -EBUSY;
cec_priv->plx_iobase = pci_resource_start(cec_priv->pci_device, 1);
nec_priv->iobase = pci_resource_start(cec_priv->pci_device, 3);
isr_flags |= IRQF_SHARED;
if (request_irq(cec_priv->pci_device->irq, cec_interrupt, isr_flags, DRV_NAME, board)) {
dev_err(board->gpib_dev, "failed to obtain IRQ %d\n", cec_priv->pci_device->irq);
return -EBUSY;
}
cec_priv->irq = cec_priv->pci_device->irq;
if (gpib_request_pseudo_irq(board, cec_interrupt)) {
dev_err(board->gpib_dev, "failed to allocate pseudo irq\n");
return -1;
}
cec_init(cec_priv, board);
// enable interrupts on plx chip
outl(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR1_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT,
cec_priv->plx_iobase + PLX9050_INTCSR_REG);
return 0;
}
static void cec_pci_detach(struct gpib_board *board)
{
struct cec_priv *cec_priv = board->private_data;
struct nec7210_priv *nec_priv;
if (cec_priv) {
nec_priv = &cec_priv->nec7210_priv;
gpib_free_pseudo_irq(board);
if (cec_priv->irq) {
// disable plx9050 interrupts
outl(0, cec_priv->plx_iobase + PLX9050_INTCSR_REG);
free_irq(cec_priv->irq, board);
}
if (nec_priv->iobase) {
nec7210_board_reset(nec_priv, board);
pci_release_regions(cec_priv->pci_device);
}
if (cec_priv->pci_device)
pci_dev_put(cec_priv->pci_device);
}
cec_free_private(board);
}
static int cec_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
return 0;
}
static const struct pci_device_id cec_pci_table[] = {
{CEC_VENDOR_ID, CEC_DEV_ID, PCI_ANY_ID, CEC_SUBID, 0, 0, 0 },
{0}
};
MODULE_DEVICE_TABLE(pci, cec_pci_table);
static struct pci_driver cec_pci_driver = {
.name = DRV_NAME,
.id_table = cec_pci_table,
.probe = &cec_pci_probe
};
static int __init cec_init_module(void)
{
int result;
result = pci_register_driver(&cec_pci_driver);
if (result) {
pr_err("pci_register_driver failed: error = %d\n", result);
return result;
}
result = gpib_register_driver(&cec_pci_interface, THIS_MODULE);
if (result) {
pr_err("gpib_register_driver failed: error = %d\n", result);
return result;
}
return 0;
}
static void cec_exit_module(void)
{
gpib_unregister_driver(&cec_pci_interface);
pci_unregister_driver(&cec_pci_driver);
}
module_init(cec_init_module);
module_exit(cec_exit_module);
+6
View File
@@ -0,0 +1,6 @@
obj-$(CONFIG_GPIB_COMMON) += gpib_common.o
gpib_common-objs := gpib_os.o iblib.o
File diff suppressed because it is too large Load Diff
+716
View File
@@ -0,0 +1,716 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2001, 2002 by Frank Mori Hess
***************************************************************************/
#define dev_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "ibsys.h"
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
/*
* IBCAC
* Return to the controller active state from the
* controller standby state, i.e., turn ATN on. Note
* that in order to enter the controller active state
* from the controller idle state, ibsic must be called.
* If sync is non-zero, attempt to take control synchronously.
* If fallback_to_async is non-zero, try to take control asynchronously
* if synchronous attempt fails.
*/
int ibcac(struct gpib_board *board, int sync, int fallback_to_async)
{
int status = ibstatus(board);
int retval;
if ((status & CIC) == 0)
return -EINVAL;
if (status & ATN)
return 0;
if (sync && (status & LACS) == 0)
/*
* tcs (take control synchronously) can only possibly work when
* controller is listener. Error code also needs to be -ETIMEDOUT
* or it will giveout without doing fallback.
*/
retval = -ETIMEDOUT;
else
retval = board->interface->take_control(board, sync);
if (retval < 0 && fallback_to_async) {
if (sync && retval == -ETIMEDOUT)
retval = board->interface->take_control(board, 0);
}
board->interface->update_status(board, 0);
return retval;
}
/*
* After ATN is asserted, it should cause any connected devices
* to start listening for command bytes and leave acceptor idle state.
* So if ATN is asserted and neither NDAC or NRFD are asserted,
* then there are no devices and ibcmd should error out immediately.
* Some gpib hardware sees itself asserting NDAC/NRFD when it
* is controller in charge, in which case this check will
* do nothing useful (but shouldn't cause any harm either).
* Drivers that don't need this check (ni_usb for example) may
* set the skip_check_for_command_acceptors flag in their
* gpib_interface_struct to avoid useless overhead.
*/
static int check_for_command_acceptors(struct gpib_board *board)
{
int lines;
if (board->interface->skip_check_for_command_acceptors)
return 0;
if (!board->interface->line_status)
return 0;
udelay(2); // allow time for devices to respond to ATN if it was just asserted
lines = board->interface->line_status(board);
if (lines < 0)
return lines;
if ((lines & VALID_NRFD) && (lines & VALID_NDAC)) {
if ((lines & BUS_NRFD) == 0 && (lines & BUS_NDAC) == 0)
return -ENOTCONN;
}
return 0;
}
/*
* IBCMD
* Write cnt command bytes from buf to the GPIB. The
* command operation terminates only on I/O complete.
*
* NOTE:
* 1. Prior to beginning the command, the interface is
* placed in the controller active state.
* 2. Before calling ibcmd for the first time, ibsic
* must be called to initialize the GPIB and enable
* the interface to leave the controller idle state.
*/
int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written)
{
ssize_t ret = 0;
int status;
*bytes_written = 0;
status = ibstatus(board);
if ((status & CIC) == 0)
return -EINVAL;
os_start_timer(board, board->usec_timeout);
ret = ibcac(board, 1, 1);
if (ret == 0) {
ret = check_for_command_acceptors(board);
if (ret == 0)
ret = board->interface->command(board, buf, length, bytes_written);
}
os_remove_timer(board);
if (io_timed_out(board))
ret = -ETIMEDOUT;
return ret;
}
/*
* IBGTS
* Go to the controller standby state from the controller
* active state, i.e., turn ATN off.
*/
int ibgts(struct gpib_board *board)
{
int status = ibstatus(board);
int retval;
if ((status & CIC) == 0)
return -EINVAL;
retval = board->interface->go_to_standby(board); /* go to standby */
board->interface->update_status(board, 0);
return retval;
}
static int autospoll_wait_should_wake_up(struct gpib_board *board)
{
int retval;
mutex_lock(&board->big_gpib_mutex);
retval = board->master && board->autospollers > 0 &&
!atomic_read(&board->stuck_srq) &&
test_and_clear_bit(SRQI_NUM, &board->status);
mutex_unlock(&board->big_gpib_mutex);
return retval;
}
static int autospoll_thread(void *board_void)
{
struct gpib_board *board = board_void;
int retval = 0;
dev_dbg(board->gpib_dev, "entering autospoll thread\n");
while (1) {
wait_event_interruptible(board->wait,
kthread_should_stop() ||
autospoll_wait_should_wake_up(board));
dev_dbg(board->gpib_dev, "autospoll wait satisfied\n");
if (kthread_should_stop())
break;
mutex_lock(&board->big_gpib_mutex);
/* make sure we are still good after we have lock */
if (board->autospollers <= 0 || board->master == 0) {
mutex_unlock(&board->big_gpib_mutex);
continue;
}
mutex_unlock(&board->big_gpib_mutex);
if (try_module_get(board->provider_module)) {
retval = autopoll_all_devices(board);
module_put(board->provider_module);
} else {
dev_err(board->gpib_dev, "try_module_get() failed!\n");
}
if (retval <= 0) {
dev_err(board->gpib_dev, "stuck SRQ\n");
atomic_set(&board->stuck_srq, 1); // XXX could be better
set_bit(SRQI_NUM, &board->status);
}
}
return retval;
}
int ibonline(struct gpib_board *board)
{
int retval;
if (board->online)
return -EBUSY;
if (!board->interface)
return -ENODEV;
retval = gpib_allocate_board(board);
if (retval < 0)
return retval;
board->dev = NULL;
board->local_ppoll_mode = 0;
retval = board->interface->attach(board, &board->config);
if (retval < 0) {
board->interface->detach(board);
return retval;
}
/*
* nios2nommu on 2.6.11 uclinux kernel has weird problems
* with autospoll thread causing huge slowdowns
*/
#ifndef CONFIG_NIOS2
board->autospoll_task = kthread_run(&autospoll_thread, board,
"gpib%d_autospoll_kthread", board->minor);
if (IS_ERR(board->autospoll_task)) {
dev_err(board->gpib_dev, "failed to create autospoll thread\n");
board->interface->detach(board);
return PTR_ERR(board->autospoll_task);
}
#endif
board->online = 1;
dev_dbg(board->gpib_dev, "board online\n");
return 0;
}
/* XXX need to make sure board is generally not in use (grab board lock?) */
int iboffline(struct gpib_board *board)
{
int retval;
if (board->online == 0)
return 0;
if (!board->interface)
return -ENODEV;
if (board->autospoll_task && !IS_ERR(board->autospoll_task)) {
retval = kthread_stop(board->autospoll_task);
if (retval)
dev_err(board->gpib_dev, "kthread_stop returned %i\n", retval);
board->autospoll_task = NULL;
}
board->interface->detach(board);
gpib_deallocate_board(board);
board->online = 0;
dev_dbg(board->gpib_dev, "board offline\n");
return 0;
}
/*
* IBLINES
* Poll the GPIB control lines and return their status in buf.
*
* LSB (bits 0-7) - VALID lines mask (lines that can be monitored).
* Next LSB (bits 8-15) - STATUS lines mask (lines that are currently set).
*
*/
int iblines(const struct gpib_board *board, short *lines)
{
int retval;
*lines = 0;
if (!board->interface->line_status)
return 0;
retval = board->interface->line_status(board);
if (retval < 0)
return retval;
*lines = retval;
return 0;
}
/*
* IBRD
* Read up to 'length' bytes of data from the GPIB into buf. End
* on detection of END (EOI and or EOS) and set 'end_flag'.
*
* NOTE:
* 1. The interface is placed in the controller standby
* state prior to beginning the read.
* 2. Prior to calling ibrd, the intended devices as well
* as the interface board itself must be addressed by
* calling ibcmd.
*/
int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *nbytes)
{
ssize_t ret = 0;
int retval;
size_t bytes_read;
*nbytes = 0;
*end_flag = 0;
if (length == 0)
return 0;
if (board->master) {
retval = ibgts(board);
if (retval < 0)
return retval;
}
/*
* XXX resetting timer here could cause timeouts take longer than they should,
* since read_ioctl calls this
* function in a loop, there is probably a similar problem with writes/commands
*/
os_start_timer(board, board->usec_timeout);
do {
ret = board->interface->read(board, buf, length - *nbytes, end_flag, &bytes_read);
if (ret < 0)
goto ibrd_out;
buf += bytes_read;
*nbytes += bytes_read;
if (need_resched())
schedule();
} while (ret == 0 && *nbytes > 0 && *nbytes < length && *end_flag == 0);
ibrd_out:
os_remove_timer(board);
return ret;
}
/*
* IBRPP
* Conduct a parallel poll and return the byte in buf.
*
* NOTE:
* 1. Prior to conducting the poll the interface is placed
* in the controller active state.
*/
int ibrpp(struct gpib_board *board, u8 *result)
{
int retval = 0;
os_start_timer(board, board->usec_timeout);
retval = ibcac(board, 1, 1);
if (retval)
return -1;
retval = board->interface->parallel_poll(board, result);
os_remove_timer(board);
return retval;
}
int ibppc(struct gpib_board *board, u8 configuration)
{
configuration &= 0x1f;
board->interface->parallel_poll_configure(board, configuration);
board->parallel_poll_configuration = configuration;
return 0;
}
int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service)
{
int board_status = ibstatus(board);
const unsigned int MSS = status_byte & request_service_bit;
if ((board_status & CIC))
return -EINVAL;
if (MSS == 0 && new_reason_for_service)
return -EINVAL;
if (board->interface->serial_poll_response2) {
board->interface->serial_poll_response2(board, status_byte, new_reason_for_service);
// fall back on simpler serial_poll_response if the behavior would be the same
} else if (board->interface->serial_poll_response &&
(MSS == 0 || (MSS && new_reason_for_service))) {
board->interface->serial_poll_response(board, status_byte);
} else {
return -EOPNOTSUPP;
}
return 0;
}
/*
* IBSIC
* Send IFC for at least 100 microseconds.
*
* NOTE:
* 1. Ibsic must be called prior to the first call to
* ibcmd in order to initialize the bus and enable the
* interface to leave the controller idle state.
*/
int ibsic(struct gpib_board *board, unsigned int usec_duration)
{
if (board->master == 0)
return -EINVAL;
if (usec_duration < 100)
usec_duration = 100;
if (usec_duration > 1000)
usec_duration = 1000;
dev_dbg(board->gpib_dev, "sending interface clear, delay = %ius\n", usec_duration);
board->interface->interface_clear(board, 1);
udelay(usec_duration);
board->interface->interface_clear(board, 0);
return 0;
}
int ibrsc(struct gpib_board *board, int request_control)
{
int retval;
if (!board->interface->request_system_control)
return -EPERM;
retval = board->interface->request_system_control(board, request_control);
if (retval)
return retval;
board->master = request_control != 0;
return 0;
}
/*
* IBSRE
* Send REN true if v is non-zero or false if v is zero.
*/
int ibsre(struct gpib_board *board, int enable)
{
if (board->master == 0)
return -EINVAL;
board->interface->remote_enable(board, enable); /* set or clear REN */
if (!enable)
usleep_range(100, 150);
return 0;
}
/*
* IBPAD
* change the GPIB address of the interface board. The address
* must be 0 through 30. ibonl resets the address to PAD.
*/
int ibpad(struct gpib_board *board, unsigned int addr)
{
if (addr > MAX_GPIB_PRIMARY_ADDRESS)
return -EINVAL;
board->pad = addr;
if (board->online)
board->interface->primary_address(board, board->pad);
dev_dbg(board->gpib_dev, "set primary addr to %i\n", board->pad);
return 0;
}
/*
* IBSAD
* change the secondary GPIB address of the interface board.
* The address must be 0 through 30, or negative disables. ibonl resets the
* address to SAD.
*/
int ibsad(struct gpib_board *board, int addr)
{
if (addr > MAX_GPIB_SECONDARY_ADDRESS)
return -EINVAL;
board->sad = addr;
if (board->online) {
if (board->sad >= 0)
board->interface->secondary_address(board, board->sad, 1);
else
board->interface->secondary_address(board, 0, 0);
}
dev_dbg(board->gpib_dev, "set secondary addr to %i\n", board->sad);
return 0;
}
/*
* IBEOS
* Set the end-of-string modes for I/O operations to v.
*
*/
int ibeos(struct gpib_board *board, int eos, int eosflags)
{
int retval;
if (eosflags & ~EOS_MASK)
return -EINVAL;
if (eosflags & REOS) {
retval = board->interface->enable_eos(board, eos, eosflags & BIN);
} else {
board->interface->disable_eos(board);
retval = 0;
}
return retval;
}
int ibstatus(struct gpib_board *board)
{
return general_ibstatus(board, NULL, 0, 0, NULL);
}
int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device,
int clear_mask, int set_mask, struct gpib_descriptor *desc)
{
int status = 0;
short line_status;
if (board->private_data) {
status = board->interface->update_status(board, clear_mask);
/*
* XXX should probably stop having drivers use TIMO bit in
* board->status to avoid confusion
*/
status &= ~TIMO;
/* get real SRQI status if we can */
if (iblines(board, &line_status) == 0) {
if ((line_status & VALID_SRQ)) {
if ((line_status & BUS_SRQ))
status |= SRQI;
else
status &= ~SRQI;
}
}
}
if (device)
if (num_status_bytes(device))
status |= RQS;
if (desc) {
if (set_mask & CMPL)
atomic_set(&desc->io_in_progress, 0);
else if (clear_mask & CMPL)
atomic_set(&desc->io_in_progress, 1);
if (atomic_read(&desc->io_in_progress))
status &= ~CMPL;
else
status |= CMPL;
}
if (num_gpib_events(&board->event_queue))
status |= EVENT;
else
status &= ~EVENT;
return status;
}
struct wait_info {
struct gpib_board *board;
struct timer_list timer;
int timed_out;
unsigned long usec_timeout;
};
static void wait_timeout(struct timer_list *t)
{
struct wait_info *winfo = timer_container_of(winfo, t, timer);
winfo->timed_out = 1;
wake_up_interruptible(&winfo->board->wait);
}
static void init_wait_info(struct wait_info *winfo)
{
winfo->board = NULL;
winfo->timed_out = 0;
timer_setup_on_stack(&winfo->timer, wait_timeout, 0);
}
static int wait_satisfied(struct wait_info *winfo, struct gpib_status_queue *status_queue,
int wait_mask, int *status, struct gpib_descriptor *desc)
{
struct gpib_board *board = winfo->board;
int temp_status;
if (mutex_lock_interruptible(&board->big_gpib_mutex))
return -ERESTARTSYS;
temp_status = general_ibstatus(board, status_queue, 0, 0, desc);
mutex_unlock(&board->big_gpib_mutex);
if (winfo->timed_out)
temp_status |= TIMO;
else
temp_status &= ~TIMO;
if (wait_mask & temp_status) {
*status = temp_status;
return 1;
}
// XXX does wait for END work?
return 0;
}
/* install timer interrupt handler */
static void start_wait_timer(struct wait_info *winfo)
/* Starts the timeout task */
{
winfo->timed_out = 0;
if (winfo->usec_timeout > 0)
mod_timer(&winfo->timer, jiffies + usec_to_jiffies(winfo->usec_timeout));
}
static void remove_wait_timer(struct wait_info *winfo)
{
timer_delete_sync(&winfo->timer);
timer_destroy_on_stack(&winfo->timer);
}
/*
* IBWAIT
* Check or wait for a GPIB event to occur. The mask argument
* is a bit vector corresponding to the status bit vector. It
* has a bit set for each condition which can terminate the wait
* If the mask is 0 then
* no condition is waited for.
*/
int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask,
int *status, unsigned long usec_timeout, struct gpib_descriptor *desc)
{
int retval = 0;
struct gpib_status_queue *status_queue;
struct wait_info winfo;
if (desc->is_board)
status_queue = NULL;
else
status_queue = get_gpib_status_queue(board, desc->pad, desc->sad);
if (wait_mask == 0) {
*status = general_ibstatus(board, status_queue, clear_mask, set_mask, desc);
return 0;
}
mutex_unlock(&board->big_gpib_mutex);
init_wait_info(&winfo);
winfo.board = board;
winfo.usec_timeout = usec_timeout;
start_wait_timer(&winfo);
if (wait_event_interruptible(board->wait, wait_satisfied(&winfo, status_queue,
wait_mask, status, desc))) {
dev_dbg(board->gpib_dev, "wait interrupted\n");
retval = -ERESTARTSYS;
}
remove_wait_timer(&winfo);
if (retval)
return retval;
if (mutex_lock_interruptible(&board->big_gpib_mutex))
return -ERESTARTSYS;
/* make sure we only clear status bits that we are reporting */
if (*status & clear_mask || set_mask)
general_ibstatus(board, status_queue, *status & clear_mask, set_mask, NULL);
return 0;
}
/*
* IBWRT
* Write cnt bytes of data from buf to the GPIB. The write
* operation terminates only on I/O complete.
*
* NOTE:
* 1. Prior to beginning the write, the interface is
* placed in the controller standby state.
* 2. Prior to calling ibwrt, the intended devices as
* well as the interface board itself must be
* addressed by calling ibcmd.
*/
int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written)
{
int ret = 0;
int retval;
if (cnt == 0)
return 0;
if (board->master) {
retval = ibgts(board);
if (retval < 0)
return retval;
}
os_start_timer(board, board->usec_timeout);
ret = board->interface->write(board, buf, cnt, send_eoi, bytes_written);
if (io_timed_out(board))
ret = -ETIMEDOUT;
os_remove_timer(board);
return ret;
}
+34
View File
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "gpibP.h"
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/dma.h>
#define MAX_GPIB_PRIMARY_ADDRESS 30
#define MAX_GPIB_SECONDARY_ADDRESS 31
int gpib_allocate_board(struct gpib_board *board);
void gpib_deallocate_board(struct gpib_board *board);
unsigned int num_status_bytes(const struct gpib_status_queue *dev);
int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device,
u8 poll_byte);
int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device,
u8 *poll_byte);
struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board,
unsigned int pad, int sad);
int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad,
unsigned int usec_timeout, u8 *poll_byte);
int autopoll_all_devices(struct gpib_board *board);
@@ -0,0 +1,3 @@
obj-$(CONFIG_GPIB_FLUKE) += fluke_gpib.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,146 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Author: Frank Mori Hess <fmh6jj@gmail.com>
* copyright: (C) 2006, 2010, 2015 Fluke Corporation
***************************************************************************/
#include <linux/compiler.h>
#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "nec7210.h"
struct fluke_priv {
struct nec7210_priv nec7210_priv;
struct resource *gpib_iomem_res;
struct resource *write_transfer_counter_res;
struct resource *dma_port_res;
int irq;
struct dma_chan *dma_channel;
u8 *dma_buffer;
int dma_buffer_size;
void __iomem *write_transfer_counter;
};
// cb7210 specific registers and bits
enum cb7210_regs {
STATE1_REG = 0x4,
ISR0_IMR0 = 0x6,
BUS_STATUS = 0x7
};
enum cb7210_page_in {
ISR0_IMR0_PAGE = 1,
BUS_STATUS_PAGE = 1,
STATE1_PAGE = 1
};
/* IMR0 -- Interrupt Mode Register 0 */
enum imr0_bits {
FLUKE_IFCIE_BIT = 0x8, /* interface clear interrupt */
};
/* ISR0 -- Interrupt Status Register 0 */
enum isr0_bits {
FLUKE_IFCI_BIT = 0x8, /* interface clear interrupt */
};
enum state1_bits {
SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */
SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */
SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */
SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */
SOURCE_HANDSHAKE_MASK = 0x7
};
/*
* we customized the cb7210 vhdl to give the "data in" status
* on the unused bit 7 of the address0 register.
*/
enum cb7210_address0 {
DATA_IN_STATUS = 0x80
};
static inline int cb7210_page_in_bits(unsigned int page)
{
return 0x50 | (page & 0xf);
}
// don't use without locking nec_priv->register_page_lock
static inline u8 fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
int register_num)
{
u8 retval;
retval = readl(nec_priv->mmiobase + register_num * nec_priv->offset);
return retval;
}
// don't use without locking nec_priv->register_page_lock
static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, u8 data,
int register_num)
{
writel(data, nec_priv->mmiobase + register_num * nec_priv->offset);
}
static inline u8 fluke_paged_read_byte(struct fluke_priv *e_priv,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
u8 retval;
unsigned long flags;
spin_lock_irqsave(&nec_priv->register_page_lock, flags);
fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
udelay(1);
/* chip auto clears the page after a read */
retval = fluke_read_byte_nolock(nec_priv, register_num);
spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
return retval;
}
static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, u8 data,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
unsigned long flags;
spin_lock_irqsave(&nec_priv->register_page_lock, flags);
fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR);
udelay(1);
fluke_write_byte_nolock(nec_priv, data, register_num);
spin_unlock_irqrestore(&nec_priv->register_page_lock, flags);
}
enum bus_status_bits {
BSR_ATN_BIT = 0x1,
BSR_EOI_BIT = 0x2,
BSR_SRQ_BIT = 0x4,
BSR_IFC_BIT = 0x8,
BSR_REN_BIT = 0x10,
BSR_DAV_BIT = 0x20,
BSR_NRFD_BIT = 0x40,
BSR_NDAC_BIT = 0x80,
};
enum cb7210_aux_cmds {
/*
* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
* (and keep asserted) local rtl message. This is used in conjunction
* with the (stupid) cb7210 implementation
* of the normal nec7210 AUX_RTL aux command, which
* causes the rtl message to toggle between on and off.
*/
AUX_RTL2 = 0xd,
AUX_NBAF = 0xe, // new byte available false (also clears seoi)
AUX_LO_SPEED = 0x40,
AUX_HI_SPEED = 0x41,
};
enum {
fluke_reg_offset = 4,
fluke_num_regs = 8,
write_transfer_counter_mask = 0x7ff,
};
@@ -0,0 +1,2 @@
obj-$(CONFIG_GPIB_FMH) += fmh_gpib.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,177 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Author: Frank Mori Hess <fmh6jj@gmail.com>
* Copyright: (C) 2006, 2010, 2015 Fluke Corporation
* (C) 2017 Frank Mori Hess
***************************************************************************/
#include <linux/dmaengine.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/io.h>
#include "nec7210.h"
static const int fifo_reg_offset = 2;
static const int gpib_control_status_pci_resource_index;
static const int gpib_fifo_pci_resource_index = 1;
/* We don't have a real pci vendor/device id, the following will need to be
* patched to match prototype hardware.
*/
#define BOGUS_PCI_VENDOR_ID_FLUKE 0xffff
#define BOGUS_PCI_DEVICE_ID_FLUKE_BLADERUNNER 0x0
struct fmh_priv {
struct nec7210_priv nec7210_priv;
struct resource *gpib_iomem_res;
struct resource *write_transfer_counter_res;
struct resource *dma_port_res;
int irq;
struct dma_chan *dma_channel;
u8 *dma_buffer;
int dma_buffer_size;
int dma_burst_length;
void __iomem *fifo_base;
unsigned supports_fifo_interrupts : 1;
};
static inline int fmh_gpib_half_fifo_size(struct fmh_priv *priv)
{
return priv->dma_burst_length;
}
// registers beyond the nec7210 register set
enum fmh_gpib_regs {
EXT_STATUS_1_REG = 0x9,
STATE1_REG = 0xc,
ISR0_IMR0_REG = 0xe,
BUS_STATUS_REG = 0xf
};
/* IMR0 -- Interrupt Mode Register 0 */
enum imr0_bits {
ATN_INTERRUPT_ENABLE_BIT = 0x4,
IFC_INTERRUPT_ENABLE_BIT = 0x8
};
/* ISR0 -- Interrupt Status Register 0 */
enum isr0_bits {
ATN_INTERRUPT_BIT = 0x4,
IFC_INTERRUPT_BIT = 0x8
};
enum state1_bits {
SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */
SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */
SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */
SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */
SOURCE_HANDSHAKE_MASK = 0x7
};
enum fmh_gpib_auxmr_bits {
AUX_I_REG = 0xe0,
};
enum aux_reg_i_bits {
LOCAL_PPOLL_MODE_BIT = 0x4
};
enum ext_status_1_bits {
DATA_IN_STATUS_BIT = 0x01,
DATA_OUT_STATUS_BIT = 0x02,
COMMAND_OUT_STATUS_BIT = 0x04,
RFD_HOLDOFF_STATUS_BIT = 0x08,
END_STATUS_BIT = 0x10
};
/* dma fifo reg and bits */
enum dma_fifo_regs {
FIFO_DATA_REG = 0x0,
FIFO_CONTROL_STATUS_REG = 0x1,
FIFO_XFER_COUNTER_REG = 0x2,
FIFO_MAX_BURST_LENGTH_REG = 0x3
};
enum fifo_data_bits {
FIFO_DATA_EOI_FLAG = 0x100
};
enum fifo_control_bits {
TX_FIFO_DMA_REQUEST_ENABLE = 0x0001,
TX_FIFO_CLEAR = 0x0002,
TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE = 0x0008,
RX_FIFO_DMA_REQUEST_ENABLE = 0x0100,
RX_FIFO_CLEAR = 0x0200,
RX_FIFO_HALF_FULL_INTERRUPT_ENABLE = 0x0800
};
enum fifo_status_bits {
TX_FIFO_EMPTY = 0x0001,
TX_FIFO_FULL = 0x0002,
TX_FIFO_HALF_EMPTY = 0x0004,
TX_FIFO_HALF_EMPTY_INTERRUPT_IS_ENABLED = 0x0008,
TX_FIFO_DMA_REQUEST_IS_ENABLED = 0x0010,
RX_FIFO_EMPTY = 0x0100,
RX_FIFO_FULL = 0x0200,
RX_FIFO_HALF_FULL = 0x0400,
RX_FIFO_HALF_FULL_INTERRUPT_IS_ENABLED = 0x0800,
RX_FIFO_DMA_REQUEST_IS_ENABLED = 0x1000
};
static const unsigned int fifo_data_mask = 0x00ff;
static const unsigned int fifo_xfer_counter_mask = 0x0fff;
static const unsigned int fifo_max_burst_length_mask = 0x00ff;
static inline u8 gpib_cs_read_byte(struct nec7210_priv *nec_priv,
unsigned int register_num)
{
return readb(nec_priv->mmiobase + register_num * nec_priv->offset);
}
static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, u8 data,
unsigned int register_num)
{
writeb(data, nec_priv->mmiobase + register_num * nec_priv->offset);
}
static inline uint16_t fifos_read(struct fmh_priv *fmh_priv, int register_num)
{
if (!fmh_priv->fifo_base)
return 0;
return readw(fmh_priv->fifo_base + register_num * fifo_reg_offset);
}
static inline void fifos_write(struct fmh_priv *fmh_priv, uint16_t data, int register_num)
{
if (!fmh_priv->fifo_base)
return;
writew(data, fmh_priv->fifo_base + register_num * fifo_reg_offset);
}
enum bus_status_bits {
BSR_ATN_BIT = 0x01,
BSR_EOI_BIT = 0x02,
BSR_SRQ_BIT = 0x04,
BSR_IFC_BIT = 0x08,
BSR_REN_BIT = 0x10,
BSR_DAV_BIT = 0x20,
BSR_NRFD_BIT = 0x40,
BSR_NDAC_BIT = 0x80,
};
enum fmh_gpib_aux_cmds {
/* AUX_RTL2 is an auxiliary command which causes the cb7210 to assert
* (and keep asserted) the local rtl message. This is used in conjunction
* with the normal nec7210 AUX_RTL command, which
* pulses the rtl message, having the effect of clearing rtl if it was left
* asserted by AUX_RTL2.
*/
AUX_RTL2 = 0x0d,
AUX_RFD_HOLDOFF_ASAP = 0x15,
AUX_REQT = 0x18,
AUX_REQF = 0x19,
AUX_LO_SPEED = 0x40,
AUX_HI_SPEED = 0x41
};
+4
View File
@@ -0,0 +1,4 @@
obj-$(CONFIG_GPIB_GPIO) += gpib_bitbang.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
obj-$(CONFIG_GPIB_HP82335) += hp82335.o
+372
View File
@@ -0,0 +1,372 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess *
***************************************************************************/
/*
* should enable ATN interrupts (and update board->status on occurrence),
* implement recovery from bus errors (if necessary)
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#define DRV_NAME KBUILD_MODNAME
#include "hp82335.h"
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for HP 82335 interface cards");
static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void hp82335_detach(struct gpib_board *board);
static irqreturn_t hp82335_interrupt(int irq, void *arg);
// wrappers for interface functions
static int hp82335_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
static int hp82335_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
static int hp82335_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written);
}
static int hp82335_take_control(struct gpib_board *board, int synchronous)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_take_control(board, &priv->tms9914_priv, synchronous);
}
static int hp82335_go_to_standby(struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
static int hp82335_request_system_control(struct gpib_board *board, int request_control)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
}
static void hp82335_interface_clear(struct gpib_board *board, int assert)
{
struct hp82335_priv *priv = board->private_data;
tms9914_interface_clear(board, &priv->tms9914_priv, assert);
}
static void hp82335_remote_enable(struct gpib_board *board, int enable)
{
struct hp82335_priv *priv = board->private_data;
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
static int hp82335_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits);
}
static void hp82335_disable_eos(struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
tms9914_disable_eos(board, &priv->tms9914_priv);
}
static unsigned int hp82335_update_status(struct gpib_board *board, unsigned int clear_mask)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_update_status(board, &priv->tms9914_priv, clear_mask);
}
static int hp82335_primary_address(struct gpib_board *board, unsigned int address)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_primary_address(board, &priv->tms9914_priv, address);
}
static int hp82335_secondary_address(struct gpib_board *board, unsigned int address, int enable)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
static int hp82335_parallel_poll(struct gpib_board *board, u8 *result)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_parallel_poll(board, &priv->tms9914_priv, result);
}
static void hp82335_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct hp82335_priv *priv = board->private_data;
tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config);
}
static void hp82335_parallel_poll_response(struct gpib_board *board, int ist)
{
struct hp82335_priv *priv = board->private_data;
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
static void hp82335_serial_poll_response(struct gpib_board *board, u8 status)
{
struct hp82335_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
static u8 hp82335_serial_poll_status(struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_serial_poll_status(board, &priv->tms9914_priv);
}
static int hp82335_line_status(const struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_line_status(board, &priv->tms9914_priv);
}
static int hp82335_t1_delay(struct gpib_board *board, unsigned int nano_sec)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_t1_delay(board, &priv->tms9914_priv, nano_sec);
}
static void hp82335_return_to_local(struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
tms9914_return_to_local(board, &priv->tms9914_priv);
}
static struct gpib_interface hp82335_interface = {
.name = "hp82335",
.attach = hp82335_attach,
.detach = hp82335_detach,
.read = hp82335_read,
.write = hp82335_write,
.command = hp82335_command,
.request_system_control = hp82335_request_system_control,
.take_control = hp82335_take_control,
.go_to_standby = hp82335_go_to_standby,
.interface_clear = hp82335_interface_clear,
.remote_enable = hp82335_remote_enable,
.enable_eos = hp82335_enable_eos,
.disable_eos = hp82335_disable_eos,
.parallel_poll = hp82335_parallel_poll,
.parallel_poll_configure = hp82335_parallel_poll_configure,
.parallel_poll_response = hp82335_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = hp82335_line_status,
.update_status = hp82335_update_status,
.primary_address = hp82335_primary_address,
.secondary_address = hp82335_secondary_address,
.serial_poll_response = hp82335_serial_poll_response,
.serial_poll_status = hp82335_serial_poll_status,
.t1_delay = hp82335_t1_delay,
.return_to_local = hp82335_return_to_local,
};
static int hp82335_allocate_private(struct gpib_board *board)
{
board->private_data = kzalloc_obj(struct hp82335_priv);
if (!board->private_data)
return -ENOMEM;
return 0;
}
static void hp82335_free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
static inline unsigned int tms9914_to_hp82335_offset(unsigned int register_num)
{
return 0x1ff8 + register_num;
}
static u8 hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return tms9914_iomem_read_byte(priv, tms9914_to_hp82335_offset(register_num));
}
static void hp82335_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
tms9914_iomem_write_byte(priv, data, tms9914_to_hp82335_offset(register_num));
}
static void hp82335_clear_interrupt(struct hp82335_priv *hp_priv)
{
struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
writeb(0, tms_priv->mmiobase + HPREG_INTR_CLEAR);
}
static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct hp82335_priv *hp_priv;
struct tms9914_priv *tms_priv;
int retval;
const unsigned long upper_iomem_base = config->ibbase + hp82335_rom_size;
board->status = 0;
retval = hp82335_allocate_private(board);
if (retval)
return retval;
hp_priv = board->private_data;
tms_priv = &hp_priv->tms9914_priv;
tms_priv->read_byte = hp82335_read_byte;
tms_priv->write_byte = hp82335_write_byte;
tms_priv->offset = 1;
switch (config->ibbase) {
case 0xc4000:
case 0xc8000:
case 0xcc000:
case 0xd0000:
case 0xd4000:
case 0xd8000:
case 0xdc000:
case 0xe0000:
case 0xe4000:
case 0xe8000:
case 0xec000:
case 0xf0000:
case 0xf4000:
case 0xf8000:
case 0xfc000:
break;
default:
dev_err(board->gpib_dev, "invalid base io address 0x%x\n", config->ibbase);
return -EINVAL;
}
if (!request_mem_region(upper_iomem_base, hp82335_upper_iomem_size, "hp82335")) {
dev_err(board->gpib_dev, "failed to allocate io memory region 0x%lx-0x%lx\n",
upper_iomem_base, upper_iomem_base + hp82335_upper_iomem_size - 1);
return -EBUSY;
}
hp_priv->raw_iobase = upper_iomem_base;
tms_priv->mmiobase = ioremap(upper_iomem_base, hp82335_upper_iomem_size);
retval = request_irq(config->ibirq, hp82335_interrupt, 0, DRV_NAME, board);
if (retval) {
dev_err(board->gpib_dev, "can't request IRQ %d\n", config->ibirq);
return retval;
}
hp_priv->irq = config->ibirq;
tms9914_board_reset(tms_priv);
hp82335_clear_interrupt(hp_priv);
writeb(INTR_ENABLE, tms_priv->mmiobase + HPREG_CCR);
tms9914_online(board, tms_priv);
return 0;
}
static void hp82335_detach(struct gpib_board *board)
{
struct hp82335_priv *hp_priv = board->private_data;
struct tms9914_priv *tms_priv;
if (hp_priv) {
tms_priv = &hp_priv->tms9914_priv;
if (hp_priv->irq)
free_irq(hp_priv->irq, board);
if (tms_priv->mmiobase) {
writeb(0, tms_priv->mmiobase + HPREG_CCR);
tms9914_board_reset(tms_priv);
iounmap(tms_priv->mmiobase);
}
if (hp_priv->raw_iobase)
release_mem_region(hp_priv->raw_iobase, hp82335_upper_iomem_size);
}
hp82335_free_private(board);
}
static int __init hp82335_init_module(void)
{
int result = gpib_register_driver(&hp82335_interface, THIS_MODULE);
if (result) {
pr_err("gpib_register_driver failed: error = %d\n", result);
return result;
}
return 0;
}
static void __exit hp82335_exit_module(void)
{
gpib_unregister_driver(&hp82335_interface);
}
module_init(hp82335_init_module);
module_exit(hp82335_exit_module);
/*
* GPIB interrupt service routines
*/
static irqreturn_t hp82335_interrupt(int irq, void *arg)
{
int status1, status2;
struct gpib_board *board = arg;
struct hp82335_priv *priv = board->private_data;
unsigned long flags;
irqreturn_t retval;
spin_lock_irqsave(&board->spinlock, flags);
status1 = read_byte(&priv->tms9914_priv, ISR0);
status2 = read_byte(&priv->tms9914_priv, ISR1);
hp82335_clear_interrupt(priv);
retval = tms9914_interrupt_have_status(board, &priv->tms9914_priv, status1, status2);
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess *
***************************************************************************/
#ifndef _HP82335_H
#define _HP82335_H
#include "tms9914.h"
#include "gpibP.h"
// struct which defines private_data for board
struct hp82335_priv {
struct tms9914_priv tms9914_priv;
unsigned int irq;
unsigned long raw_iobase;
};
// size of io memory region used
static const int hp82335_rom_size = 0x2000;
static const int hp82335_upper_iomem_size = 0x2000;
// hp82335 register offsets
enum hp_read_regs {
HPREG_CSR = 0x17f8,
HPREG_STATUS = 0x1ffc,
};
enum hp_write_regs {
HPREG_INTR_CLEAR = 0x17f7,
HPREG_CCR = HPREG_CSR,
};
enum ccr_bits {
DMA_ENABLE = (1 << 0), /* DMA enable */
DMA_CHAN_SELECT = (1 << 1), /* DMA channel select O=3,1=2 */
INTR_ENABLE = (1 << 2), /* interrupt enable */
SYS_DISABLE = (1 << 3), /* system controller disable */
};
enum csr_bits {
SWITCH6 = (1 << 0), /* switch 6 position */
SWITCH5 = (1 << 1), /* switch 5 position */
SYS_CONTROLLER = (1 << 2), /* system controller bit */
DMA_ENABLE_STATUS = (1 << 4), /* DMA enabled */
DMA_CHAN_STATUS = (1 << 5), /* DMA channel 0=3,1=2 */
INTR_ENABLE_STATUS = (1 << 6), /* Interrupt enable */
INTR_PENDING = (1 << 7), /* Interrupt Pending */
};
#endif // _HP82335_H
@@ -0,0 +1,2 @@
obj-$(CONFIG_GPIB_HP82341) += hp_82341.o
@@ -0,0 +1,908 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* Driver for hp 82341a/b/c/d boards. *
* Might be worth merging with Agilent 82350b driver. *
* copyright : (C) 2002, 2005 by Frank Mori Hess *
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#define DRV_NAME KBUILD_MODNAME
#include "hp_82341.h"
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/isapnp.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for hp 82341a/b/c/d boards");
static unsigned short read_and_clear_event_status(struct gpib_board *board);
static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count);
static int read_transfer_counter(struct hp_82341_priv *hp_priv);
static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written);
static irqreturn_t hp_82341_interrupt(int irq, void *arg);
static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct hp_82341_priv *hp_priv = board->private_data;
struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
int retval = 0;
unsigned short event_status;
int i;
int num_fifo_bytes;
// hardware doesn't support checking for end-of-string character when using fifo
if (tms_priv->eos_flags & REOS)
return tms9914_read(board, tms_priv, buffer, length, end, bytes_read);
clear_bit(DEV_CLEAR_BN, &tms_priv->state);
read_and_clear_event_status(board);
*end = 0;
*bytes_read = 0;
if (length == 0)
return 0;
// disable fifo for the moment
outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
/*
* Handle corner case of board not in holdoff and one byte has slipped in already.
* Also, board sometimes has problems (spurious 1 byte reads) when read fifo is
* started up with board in TACS under certain data holdoff conditions.
* Doing a 1 byte tms9914-style read avoids these problems.
*/
if (/*tms_priv->holdoff_active == 0 && */length > 1) {
size_t num_bytes;
retval = tms9914_read(board, tms_priv, buffer, 1, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
dev_err(board->gpib_dev, "tms9914_read failed retval=%i\n", retval);
if (retval < 0 || *end)
return retval;
++buffer;
--length;
}
tms9914_set_holdoff_mode(tms_priv, TMS9914_HOLDOFF_EOI);
tms9914_release_holdoff(tms_priv);
outb(0x00, hp_priv->iobase[3] + BUFFER_FLUSH_REG);
i = 0;
num_fifo_bytes = length - 1;
while (i < num_fifo_bytes && *end == 0) {
int block_size;
int j;
int count;
block_size = min(num_fifo_bytes - i, hp_82341_fifo_size);
set_transfer_counter(hp_priv, block_size);
outb(ENABLE_TI_BUFFER_BIT | DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] +
BUFFER_CONTROL_REG);
if (inb(hp_priv->iobase[0] + STREAM_STATUS_REG) & HALTED_STATUS_BIT)
outb(RESTART_STREAM_BIT, hp_priv->iobase[0] + STREAM_STATUS_REG);
clear_bit(READ_READY_BN, &tms_priv->state);
retval = wait_event_interruptible(board->wait,
((event_status =
read_and_clear_event_status(board)) &
(TERMINAL_COUNT_EVENT_BIT |
BUFFER_END_EVENT_BIT)) ||
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(TIMO_NUM, &board->status));
if (retval) {
retval = -ERESTARTSYS;
break;
}
// have to disable buffer before we can read from buffer port
outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
count = block_size - read_transfer_counter(hp_priv);
j = 0;
while (j < count && i < num_fifo_bytes) {
unsigned short data_word = inw(hp_priv->iobase[3] + BUFFER_PORT_LOW_REG);
buffer[i++] = data_word & 0xff;
++j;
if (j < count && i < num_fifo_bytes) {
buffer[i++] = (data_word >> 8) & 0xff;
++j;
}
}
if (event_status & BUFFER_END_EVENT_BIT) {
clear_bit(RECEIVED_END_BN, &tms_priv->state);
*end = 1;
tms_priv->holdoff_active = 1;
}
if (test_bit(TIMO_NUM, &board->status)) {
retval = -ETIMEDOUT;
break;
}
if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) {
retval = -EINTR;
break;
}
}
*bytes_read += i;
buffer += i;
length -= i;
if (retval < 0)
return retval;
// read last byte if we havn't received an END yet
if (*end == 0) {
size_t num_bytes;
// try to make sure we holdoff after last byte read
retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
return retval;
}
return 0;
}
static int restart_write_fifo(struct gpib_board *board, struct hp_82341_priv *hp_priv)
{
struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
if ((inb(hp_priv->iobase[0] + STREAM_STATUS_REG) & HALTED_STATUS_BIT) == 0)
return 0;
while (1) {
int status;
// restart doesn't work if data holdoff is in effect
status = tms9914_line_status(board, tms_priv);
if ((status & BUS_NRFD) == 0) {
outb(RESTART_STREAM_BIT, hp_priv->iobase[0] + STREAM_STATUS_REG);
return 0;
}
if (test_bit(DEV_CLEAR_BN, &tms_priv->state))
return -EINTR;
if (test_bit(TIMO_NUM, &board->status))
return -ETIMEDOUT;
if (msleep_interruptible(1))
return -EINTR;
}
return 0;
}
static int hp_82341_accel_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct hp_82341_priv *hp_priv = board->private_data;
struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
int i, j;
unsigned short event_status;
int retval = 0;
int fifo_xfer_len = length;
*bytes_written = 0;
if (send_eoi)
--fifo_xfer_len;
clear_bit(DEV_CLEAR_BN, &tms_priv->state);
read_and_clear_event_status(board);
outb(0, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
outb(0x00, hp_priv->iobase[3] + BUFFER_FLUSH_REG);
for (i = 0; i < fifo_xfer_len;) {
int block_size;
block_size = min(fifo_xfer_len - i, hp_82341_fifo_size);
set_transfer_counter(hp_priv, block_size);
// load data into board's fifo
for (j = 0; j < block_size;) {
unsigned short data_word = buffer[i++];
++j;
if (j < block_size) {
data_word |= buffer[i++] << 8;
++j;
}
outw(data_word, hp_priv->iobase[3] + BUFFER_PORT_LOW_REG);
}
clear_bit(WRITE_READY_BN, &tms_priv->state);
outb(ENABLE_TI_BUFFER_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
retval = restart_write_fifo(board, hp_priv);
if (retval < 0) {
dev_err(board->gpib_dev, "failed to restart write stream\n");
break;
}
retval = wait_event_interruptible(board->wait,
((event_status =
read_and_clear_event_status(board)) &
TERMINAL_COUNT_EVENT_BIT) ||
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(TIMO_NUM, &board->status));
outb(0, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
*bytes_written += block_size - read_transfer_counter(hp_priv);
if (retval) {
retval = -ERESTARTSYS;
break;
}
if (test_bit(TIMO_NUM, &board->status)) {
retval = -ETIMEDOUT;
break;
}
if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) {
retval = -EINTR;
break;
}
}
if (retval)
return retval;
if (send_eoi) {
size_t num_bytes;
retval = hp_82341_write(board, buffer + fifo_xfer_len, 1, 1, &num_bytes);
*bytes_written += num_bytes;
if (retval < 0)
return retval;
}
return 0;
}
static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void hp_82341_detach(struct gpib_board *board);
// wrappers for interface functions
static int hp_82341_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
static int hp_82341_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written);
}
static int hp_82341_take_control(struct gpib_board *board, int synchronous)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_take_control(board, &priv->tms9914_priv, synchronous);
}
static int hp_82341_go_to_standby(struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
static int hp_82341_request_system_control(struct gpib_board *board, int request_control)
{
struct hp_82341_priv *priv = board->private_data;
if (request_control)
priv->mode_control_bits |= SYSTEM_CONTROLLER_BIT;
else
priv->mode_control_bits &= ~SYSTEM_CONTROLLER_BIT;
outb(priv->mode_control_bits, priv->iobase[0] + MODE_CONTROL_STATUS_REG);
return tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
}
static void hp_82341_interface_clear(struct gpib_board *board, int assert)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_interface_clear(board, &priv->tms9914_priv, assert);
}
static void hp_82341_remote_enable(struct gpib_board *board, int enable)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
static int hp_82341_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits);
}
static void hp_82341_disable_eos(struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_disable_eos(board, &priv->tms9914_priv);
}
static unsigned int hp_82341_update_status(struct gpib_board *board, unsigned int clear_mask)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_update_status(board, &priv->tms9914_priv, clear_mask);
}
static int hp_82341_primary_address(struct gpib_board *board, unsigned int address)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_primary_address(board, &priv->tms9914_priv, address);
}
static int hp_82341_secondary_address(struct gpib_board *board, unsigned int address, int enable)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
static int hp_82341_parallel_poll(struct gpib_board *board, u8 *result)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_parallel_poll(board, &priv->tms9914_priv, result);
}
static void hp_82341_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config);
}
static void hp_82341_parallel_poll_response(struct gpib_board *board, int ist)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
static void hp_82341_serial_poll_response(struct gpib_board *board, u8 status)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
static u8 hp_82341_serial_poll_status(struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_serial_poll_status(board, &priv->tms9914_priv);
}
static int hp_82341_line_status(const struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_line_status(board, &priv->tms9914_priv);
}
static int hp_82341_t1_delay(struct gpib_board *board, unsigned int nano_sec)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_t1_delay(board, &priv->tms9914_priv, nano_sec);
}
static void hp_82341_return_to_local(struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_return_to_local(board, &priv->tms9914_priv);
}
static struct gpib_interface hp_82341_unaccel_interface = {
.name = "hp_82341_unaccel",
.attach = hp_82341_attach,
.detach = hp_82341_detach,
.read = hp_82341_read,
.write = hp_82341_write,
.command = hp_82341_command,
.request_system_control = hp_82341_request_system_control,
.take_control = hp_82341_take_control,
.go_to_standby = hp_82341_go_to_standby,
.interface_clear = hp_82341_interface_clear,
.remote_enable = hp_82341_remote_enable,
.enable_eos = hp_82341_enable_eos,
.disable_eos = hp_82341_disable_eos,
.parallel_poll = hp_82341_parallel_poll,
.parallel_poll_configure = hp_82341_parallel_poll_configure,
.parallel_poll_response = hp_82341_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = hp_82341_line_status,
.update_status = hp_82341_update_status,
.primary_address = hp_82341_primary_address,
.secondary_address = hp_82341_secondary_address,
.serial_poll_response = hp_82341_serial_poll_response,
.serial_poll_status = hp_82341_serial_poll_status,
.t1_delay = hp_82341_t1_delay,
.return_to_local = hp_82341_return_to_local,
};
static struct gpib_interface hp_82341_interface = {
.name = "hp_82341",
.attach = hp_82341_attach,
.detach = hp_82341_detach,
.read = hp_82341_accel_read,
.write = hp_82341_accel_write,
.command = hp_82341_command,
.request_system_control = hp_82341_request_system_control,
.take_control = hp_82341_take_control,
.go_to_standby = hp_82341_go_to_standby,
.interface_clear = hp_82341_interface_clear,
.remote_enable = hp_82341_remote_enable,
.enable_eos = hp_82341_enable_eos,
.disable_eos = hp_82341_disable_eos,
.parallel_poll = hp_82341_parallel_poll,
.parallel_poll_configure = hp_82341_parallel_poll_configure,
.parallel_poll_response = hp_82341_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = hp_82341_line_status,
.update_status = hp_82341_update_status,
.primary_address = hp_82341_primary_address,
.secondary_address = hp_82341_secondary_address,
.serial_poll_response = hp_82341_serial_poll_response,
.t1_delay = hp_82341_t1_delay,
.return_to_local = hp_82341_return_to_local,
};
static int hp_82341_allocate_private(struct gpib_board *board)
{
board->private_data = kzalloc_obj(struct hp_82341_priv);
if (!board->private_data)
return -ENOMEM;
return 0;
}
static void hp_82341_free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
static u8 hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return inb(priv->iobase + register_num);
}
static void hp_82341_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
outb(data, priv->iobase + register_num);
}
static int hp_82341_find_isapnp_board(struct pnp_dev **dev)
{
*dev = pnp_find_dev(NULL, ISAPNP_VENDOR('H', 'W', 'P'),
ISAPNP_FUNCTION(0x1411), NULL);
if (!*dev || !(*dev)->card) {
pr_err("failed to find isapnp board\n");
return -ENODEV;
}
if (pnp_device_attach(*dev) < 0) {
pr_err("board already active, skipping\n");
return -EBUSY;
}
if (pnp_activate_dev(*dev) < 0) {
pnp_device_detach(*dev);
pr_err("failed to activate(), aborting\n");
return -EAGAIN;
}
if (!pnp_port_valid(*dev, 0) || !pnp_irq_valid(*dev, 0)) {
pnp_device_detach(*dev);
pr_err("invalid port or irq, aborting\n");
return -ENOMEM;
}
return 0;
}
static int xilinx_ready(struct hp_82341_priv *hp_priv)
{
switch (hp_priv->hw_version) {
case HW_VERSION_82341C:
if (inb(hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG) & XILINX_READY_BIT)
return 1;
else
return 0;
break;
case HW_VERSION_82341D:
if (isapnp_read_byte(PIO_DATA_REG) & HP_82341D_XILINX_READY_BIT)
return 1;
else
return 0;
default:
pr_err("bug! unknown hw_version\n");
break;
}
return 0;
}
static int xilinx_done(struct hp_82341_priv *hp_priv)
{
switch (hp_priv->hw_version) {
case HW_VERSION_82341C:
if (inb(hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG) & DONE_PGL_BIT)
return 1;
else
return 0;
case HW_VERSION_82341D:
if (isapnp_read_byte(PIO_DATA_REG) & HP_82341D_XILINX_DONE_BIT)
return 1;
else
return 0;
default:
pr_err("bug! unknown hw_version\n");
break;
}
return 0;
}
static int irq_valid(struct hp_82341_priv *hp_priv, int irq)
{
switch (hp_priv->hw_version) {
case HW_VERSION_82341C:
switch (irq) {
case 3:
case 5:
case 7:
case 9:
case 10:
case 11:
case 12:
case 15:
return 1;
default:
pr_err("invalid irq=%i for 82341C, irq must be 3, 5, 7, 9, 10, 11, 12, or 15.\n",
irq);
return 0;
}
break;
case HW_VERSION_82341D:
return 1;
default:
pr_err("bug! unknown hw_version\n");
break;
}
return 0;
}
static int hp_82341_load_firmware_array(struct hp_82341_priv *hp_priv,
const unsigned char *firmware_data,
unsigned int firmware_length)
{
int i, j;
static const int timeout = 100;
for (i = 0; i < firmware_length; ++i) {
for (j = 0; j < timeout; ++j) {
if (need_resched())
schedule();
if (xilinx_ready(hp_priv))
break;
usleep_range(10, 15);
}
if (j == timeout) {
pr_err("timed out waiting for Xilinx ready.\n");
return -ETIMEDOUT;
}
outb(firmware_data[i], hp_priv->iobase[0] + XILINX_DATA_REG);
}
for (j = 0; j < timeout; ++j) {
if (xilinx_done(hp_priv))
break;
if (need_resched())
schedule();
usleep_range(10, 15);
}
if (j == timeout) {
pr_err("timed out waiting for Xilinx done.\n");
return -ETIMEDOUT;
}
return 0;
}
static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv,
const struct gpib_board_config *config)
{
if (config->init_data_length == 0) {
if (xilinx_done(hp_priv))
return 0;
pr_err("board needs be initialized with firmware upload.\n"
"\tUse the --init-data option of gpib_config.\n");
return -EINVAL;
}
switch (hp_priv->hw_version) {
case HW_VERSION_82341C:
if (config->init_data_length != hp_82341c_firmware_length) {
pr_err("bad firmware length=%i for 82341c (expected %i).\n",
config->init_data_length, hp_82341c_firmware_length);
return -EINVAL;
}
break;
case HW_VERSION_82341D:
if (config->init_data_length != hp_82341d_firmware_length) {
pr_err("bad firmware length=%i for 82341d (expected %i).\n",
config->init_data_length, hp_82341d_firmware_length);
return -EINVAL;
}
break;
default:
pr_err("bug! unknown hw_version\n");
break;
}
return hp_82341_load_firmware_array(hp_priv, config->init_data, config->init_data_length);
}
static void set_xilinx_not_prog(struct hp_82341_priv *hp_priv, int assert)
{
switch (hp_priv->hw_version) {
case HW_VERSION_82341C:
if (assert)
hp_priv->config_control_bits |= DONE_PGL_BIT;
else
hp_priv->config_control_bits &= ~DONE_PGL_BIT;
outb(hp_priv->config_control_bits, hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG);
break;
case HW_VERSION_82341D:
if (assert)
isapnp_write_byte(PIO_DATA_REG, HP_82341D_NOT_PROG_BIT);
else
isapnp_write_byte(PIO_DATA_REG, 0x0);
break;
default:
break;
}
}
// clear xilinx firmware
static int clear_xilinx(struct hp_82341_priv *hp_priv)
{
set_xilinx_not_prog(hp_priv, 1);
if (msleep_interruptible(1))
return -EINTR;
set_xilinx_not_prog(hp_priv, 0);
if (msleep_interruptible(1))
return -EINTR;
set_xilinx_not_prog(hp_priv, 1);
if (msleep_interruptible(1))
return -EINTR;
return 0;
}
static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct hp_82341_priv *hp_priv;
struct tms9914_priv *tms_priv;
u32 start_addr;
u32 iobase;
int irq;
int i;
int retval;
board->status = 0;
retval = hp_82341_allocate_private(board);
if (retval)
return retval;
hp_priv = board->private_data;
tms_priv = &hp_priv->tms9914_priv;
tms_priv->read_byte = hp_82341_read_byte;
tms_priv->write_byte = hp_82341_write_byte;
tms_priv->offset = 1;
if (config->ibbase == 0) {
struct pnp_dev *dev;
int retval = hp_82341_find_isapnp_board(&dev);
if (retval < 0)
return retval;
hp_priv->pnp_dev = dev;
iobase = pnp_port_start(dev, 0);
irq = pnp_irq(dev, 0);
hp_priv->hw_version = HW_VERSION_82341D;
hp_priv->io_region_offset = 0x8;
} else {
iobase = config->ibbase;
irq = config->ibirq;
hp_priv->hw_version = HW_VERSION_82341C;
hp_priv->io_region_offset = 0x400;
}
for (i = 0; i < hp_82341_num_io_regions; ++i) {
start_addr = iobase + i * hp_priv->io_region_offset;
if (!request_region(start_addr, hp_82341_region_iosize, DRV_NAME)) {
dev_err(board->gpib_dev, "failed to allocate io ports 0x%x-0x%x\n",
start_addr,
start_addr + hp_82341_region_iosize - 1);
return -EIO;
}
hp_priv->iobase[i] = start_addr;
}
tms_priv->iobase = hp_priv->iobase[2];
if (hp_priv->hw_version == HW_VERSION_82341D) {
retval = isapnp_cfg_begin(hp_priv->pnp_dev->card->number,
hp_priv->pnp_dev->number);
if (retval < 0) {
dev_err(board->gpib_dev, "isapnp_cfg_begin returned error\n");
return retval;
}
isapnp_write_byte(PIO_DIRECTION_REG, HP_82341D_XILINX_READY_BIT |
HP_82341D_XILINX_DONE_BIT);
}
retval = clear_xilinx(hp_priv);
if (retval < 0)
return retval;
retval = hp_82341_load_firmware(hp_priv, config);
if (hp_priv->hw_version == HW_VERSION_82341D)
isapnp_cfg_end();
if (retval < 0)
return retval;
if (irq_valid(hp_priv, irq) == 0)
return -EINVAL;
if (request_irq(irq, hp_82341_interrupt, 0, DRV_NAME, board)) {
dev_err(board->gpib_dev, "failed to allocate IRQ %d\n", irq);
return -EIO;
}
hp_priv->irq = irq;
hp_priv->config_control_bits &= ~IRQ_SELECT_MASK;
hp_priv->config_control_bits |= IRQ_SELECT_BITS(irq);
outb(hp_priv->config_control_bits, hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG);
hp_priv->mode_control_bits |= ENABLE_IRQ_CONFIG_BIT;
outb(hp_priv->mode_control_bits, hp_priv->iobase[0] + MODE_CONTROL_STATUS_REG);
tms9914_board_reset(tms_priv);
outb(ENABLE_BUFFER_END_EVENT_BIT | ENABLE_TERMINAL_COUNT_EVENT_BIT |
ENABLE_TI_INTERRUPT_EVENT_BIT, hp_priv->iobase[0] + EVENT_ENABLE_REG);
outb(ENABLE_BUFFER_END_INTERRUPT_BIT | ENABLE_TERMINAL_COUNT_INTERRUPT_BIT |
ENABLE_TI_INTERRUPT_BIT, hp_priv->iobase[0] + INTERRUPT_ENABLE_REG);
// write clear event register
outb((TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT |
BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT),
hp_priv->iobase[0] + EVENT_STATUS_REG);
tms9914_online(board, tms_priv);
return 0;
}
static void hp_82341_detach(struct gpib_board *board)
{
struct hp_82341_priv *hp_priv = board->private_data;
struct tms9914_priv *tms_priv;
int i;
if (hp_priv) {
tms_priv = &hp_priv->tms9914_priv;
if (hp_priv->iobase[0]) {
outb(0, hp_priv->iobase[0] + INTERRUPT_ENABLE_REG);
if (tms_priv->iobase)
tms9914_board_reset(tms_priv);
if (hp_priv->irq)
free_irq(hp_priv->irq, board);
}
for (i = 0; i < hp_82341_num_io_regions; ++i) {
if (hp_priv->iobase[i])
release_region(hp_priv->iobase[i], hp_82341_region_iosize);
}
if (hp_priv->pnp_dev)
pnp_device_detach(hp_priv->pnp_dev);
}
hp_82341_free_private(board);
}
#if 0
/* unused, will be needed when the driver is turned into a pnp_driver */
static const struct pnp_device_id hp_82341_pnp_table[] = {
{.id = "HWP1411"},
{.id = ""}
};
MODULE_DEVICE_TABLE(pnp, hp_82341_pnp_table);
#endif
static int __init hp_82341_init_module(void)
{
int ret;
ret = gpib_register_driver(&hp_82341_unaccel_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
return ret;
}
ret = gpib_register_driver(&hp_82341_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
gpib_unregister_driver(&hp_82341_unaccel_interface);
return ret;
}
return 0;
}
static void __exit hp_82341_exit_module(void)
{
gpib_unregister_driver(&hp_82341_interface);
gpib_unregister_driver(&hp_82341_unaccel_interface);
}
module_init(hp_82341_init_module);
module_exit(hp_82341_exit_module);
/*
* GPIB interrupt service routines
*/
static unsigned short read_and_clear_event_status(struct gpib_board *board)
{
struct hp_82341_priv *hp_priv = board->private_data;
unsigned long flags;
unsigned short status;
spin_lock_irqsave(&board->spinlock, flags);
status = hp_priv->event_status_bits;
hp_priv->event_status_bits = 0;
spin_unlock_irqrestore(&board->spinlock, flags);
return status;
}
static irqreturn_t hp_82341_interrupt(int irq, void *arg)
{
int status1, status2;
struct gpib_board *board = arg;
struct hp_82341_priv *hp_priv = board->private_data;
struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv;
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
int event_status;
spin_lock_irqsave(&board->spinlock, flags);
event_status = inb(hp_priv->iobase[0] + EVENT_STATUS_REG);
if (event_status & INTERRUPT_PENDING_EVENT_BIT)
retval = IRQ_HANDLED;
// write-clear status bits
if (event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT |
BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT)) {
outb(event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT |
BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT),
hp_priv->iobase[0] + EVENT_STATUS_REG);
hp_priv->event_status_bits |= event_status;
}
if (event_status & TI_INTERRUPT_EVENT_BIT) {
status1 = read_byte(tms_priv, ISR0);
status2 = read_byte(tms_priv, ISR1);
tms9914_interrupt_have_status(board, tms_priv, status1, status2);
}
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
static int read_transfer_counter(struct hp_82341_priv *hp_priv)
{
int lo, mid, value;
lo = inb(hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG);
mid = inb(hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG);
value = (lo & 0xff) | ((mid << 8) & 0x7f00);
value = ~(value - 1) & 0x7fff;
return value;
}
static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count)
{
int complement = -count;
outb(complement & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG);
outb((complement >> 8) & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG);
// I don't think the hi count reg is even used, but oh well
outb((complement >> 16) & 0xf, hp_priv->iobase[1] + TRANSFER_COUNT_HIGH_REG);
}
@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002, 2005 by Frank Mori Hess *
***************************************************************************/
#include "tms9914.h"
#include "gpibP.h"
enum hp_82341_hardware_version {
HW_VERSION_UNKNOWN,
HW_VERSION_82341C,
HW_VERSION_82341D,
};
// struct which defines private_data for board
struct hp_82341_priv {
struct tms9914_priv tms9914_priv;
unsigned int irq;
unsigned short config_control_bits;
unsigned short mode_control_bits;
unsigned short event_status_bits;
struct pnp_dev *pnp_dev;
unsigned long iobase[4];
unsigned long io_region_offset;
enum hp_82341_hardware_version hw_version;
};
static const int hp_82341_region_iosize = 0x8;
static const int hp_82341_num_io_regions = 4;
static const int hp_82341_fifo_size = 0xffe;
static const int hp_82341c_firmware_length = 5764;
static const int hp_82341d_firmware_length = 5302;
// hp 82341 register offsets
enum hp_82341_region_0_registers {
CONFIG_CONTROL_STATUS_REG = 0x0,
MODE_CONTROL_STATUS_REG = 0x1,
MONITOR_REG = 0x2, // after initialization
XILINX_DATA_REG = 0x2, // before initialization, write only
INTERRUPT_ENABLE_REG = 0x3,
EVENT_STATUS_REG = 0x4,
EVENT_ENABLE_REG = 0x5,
STREAM_STATUS_REG = 0x7,
};
enum hp_82341_region_1_registers {
ID0_REG = 0x2,
ID1_REG = 0x3,
TRANSFER_COUNT_LOW_REG = 0x4,
TRANSFER_COUNT_MID_REG = 0x5,
TRANSFER_COUNT_HIGH_REG = 0x6,
};
enum hp_82341_region_3_registers {
BUFFER_PORT_LOW_REG = 0x0,
BUFFER_PORT_HIGH_REG = 0x1,
ID2_REG = 0x2,
ID3_REG = 0x3,
BUFFER_FLUSH_REG = 0x4,
BUFFER_CONTROL_REG = 0x7
};
enum config_control_status_bits {
IRQ_SELECT_MASK = 0x7,
DMA_CONFIG_MASK = 0x18,
ENABLE_DMA_CONFIG_BIT = 0x20,
XILINX_READY_BIT = 0x40, // read only
DONE_PGL_BIT = 0x80
};
static inline unsigned int IRQ_SELECT_BITS(int irq)
{
switch (irq) {
case 3:
return 0x3;
case 5:
return 0x2;
case 7:
return 0x1;
case 9:
return 0x0;
case 10:
return 0x7;
case 11:
return 0x6;
case 12:
return 0x5;
case 15:
return 0x4;
default:
return 0x0;
}
};
enum mode_control_status_bits {
SLOT8_BIT = 0x1, // read only
ACTIVE_CONTROLLER_BIT = 0x2, // read only
ENABLE_DMA_BIT = 0x4,
SYSTEM_CONTROLLER_BIT = 0x8,
MONITOR_BIT = 0x10,
ENABLE_IRQ_CONFIG_BIT = 0x20,
ENABLE_TI_STREAM_BIT = 0x40
};
enum monitor_bits {
MONITOR_INTERRUPT_PENDING_BIT = 0x1, // read only
MONITOR_CLEAR_HOLDOFF_BIT = 0x2, // write only
MONITOR_PPOLL_BIT = 0x4, // write clear
MONITOR_SRQ_BIT = 0x8, // write clear
MONITOR_IFC_BIT = 0x10, // write clear
MONITOR_REN_BIT = 0x20, // write clear
MONITOR_END_BIT = 0x40, // write clear
MONITOR_DAV_BIT = 0x80 // write clear
};
enum interrupt_enable_bits {
ENABLE_TI_INTERRUPT_BIT = 0x1,
ENABLE_POINTERS_EQUAL_INTERRUPT_BIT = 0x4,
ENABLE_BUFFER_END_INTERRUPT_BIT = 0x10,
ENABLE_TERMINAL_COUNT_INTERRUPT_BIT = 0x20,
ENABLE_DMA_TERMINAL_COUNT_INTERRUPT_BIT = 0x80,
};
enum event_status_bits {
TI_INTERRUPT_EVENT_BIT = 0x1, // write clear
INTERRUPT_PENDING_EVENT_BIT = 0x2, // read only
POINTERS_EQUAL_EVENT_BIT = 0x4, // write clear
BUFFER_END_EVENT_BIT = 0x10, // write clear
TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear
DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear
};
enum event_enable_bits {
ENABLE_TI_INTERRUPT_EVENT_BIT = 0x1, // write clear
ENABLE_POINTERS_EQUAL_EVENT_BIT = 0x4, // write clear
ENABLE_BUFFER_END_EVENT_BIT = 0x10, // write clear
ENABLE_TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear
ENABLE_DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear
};
enum stream_status_bits {
HALTED_STATUS_BIT = 0x1, // read
RESTART_STREAM_BIT = 0x1 // write
};
enum buffer_control_bits {
DIRECTION_GPIB_TO_HOST_BIT = 0x20, // transfer direction (set for gpib to host)
ENABLE_TI_BUFFER_BIT = 0x40, // enable fifo
FAST_WR_EN_BIT = 0x80, // 350 ns t1 delay?
};
// registers accessible through isapnp chip on 82341d
enum hp_82341d_pnp_registers {
PIO_DATA_REG = 0x20, // read/write pio data lines
PIO_DIRECTION_REG = 0x21, // set pio data line directions (set for input)
};
enum hp_82341d_pnp_pio_bits {
HP_82341D_XILINX_READY_BIT = 0x1,
HP_82341D_XILINX_DONE_BIT = 0x2,
// use register layout compatible with C and older versions instead of 32 contiguous ioports
HP_82341D_LEGACY_MODE_BIT = 0x4,
HP_82341D_NOT_PROG_BIT = 0x8, // clear to reinitialize xilinx
};
@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Header for amcc5920 pci chip
*
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
// plx pci chip registers and bits
enum amcc_registers {
AMCC_INTCS_REG = 0x38,
AMCC_PASS_THRU_REG = 0x60,
};
enum amcc_incsr_bits {
AMCC_ADDON_INTR_ENABLE_BIT = 0x2000,
AMCC_ADDON_INTR_ACTIVE_BIT = 0x400000,
AMCC_INTR_ACTIVE_BIT = 0x800000,
};
static const int bits_per_region = 8;
static inline uint32_t amcc_wait_state_bits(unsigned int region, unsigned int num_wait_states)
{
return (num_wait_states & 0x7) << (--region * bits_per_region);
};
enum amcc_prefetch_bits {
PREFETCH_DISABLED = 0x0,
PREFETCH_SMALL = 0x8,
PREFETCH_MEDIUM = 0x10,
PREFETCH_LARGE = 0x18,
};
static inline uint32_t amcc_prefetch_bits(unsigned int region, enum amcc_prefetch_bits prefetch)
{
return prefetch << (--region * bits_per_region);
};
static inline uint32_t amcc_PTADR_mode_bit(unsigned int region)
{
return 0x80 << (--region * bits_per_region);
};
static inline uint32_t amcc_disable_write_fifo_bit(unsigned int region)
{
return 0x20 << (--region * bits_per_region);
};
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Registers and bits for amccs5933 pci chip
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
// register offsets
enum {
MBEF_REG = 0x34, // mailbux empty/full
INTCSR_REG = 0x38, // interrupt control and status
BMCSR_REG = 0x3c, // bus master control and status
};
// incoming mailbox 0-3 register offsets
extern inline int INCOMING_MAILBOX_REG(unsigned int mailbox)
{
return (0x10 + 4 * mailbox);
};
// bit definitions
// INTCSR bits
enum {
OUTBOX_EMPTY_INTR_BIT = 0x10, // enable outbox empty interrupt
INBOX_FULL_INTR_BIT = 0x1000, // enable inbox full interrupt
INBOX_INTR_CS_BIT = 0x20000, // read, or write clear inbox full interrupt
INTR_ASSERTED_BIT = 0x800000, // read only, interrupt asserted
};
// select byte 0 to 3 of incoming mailbox
extern inline int INBOX_BYTE_BITS(unsigned int byte)
{
return (byte & 0x3) << 8;
};
// select incoming mailbox 0 to 3
extern inline int INBOX_SELECT_BITS(unsigned int mailbox)
{
return (mailbox & 0x3) << 10;
};
// select byte 0 to 3 of outgoing mailbox
extern inline int OUTBOX_BYTE_BITS(unsigned int byte)
{
return (byte & 0x3);
};
// select outgoing mailbox 0 to 3
extern inline int OUTBOX_SELECT_BITS(unsigned int mailbox)
{
return (mailbox & 0x3) << 2;
};
// BMCSR bits
enum {
MBOX_FLAGS_RESET_BIT = 0x08000000, // resets mailbox empty/full flags
};
+41
View File
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002,2003 by Frank Mori Hess
***************************************************************************/
#ifndef _GPIB_P_H
#define _GPIB_P_H
#include <linux/types.h>
#include "gpib_types.h"
#include "gpib_proto.h"
#include "gpib_cmd.h"
#include <linux/gpib.h>
#include <linux/gpib_ioctl.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
int gpib_register_driver(struct gpib_interface *interface, struct module *mod);
void gpib_unregister_driver(struct gpib_interface *interface);
struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, struct pci_dev *from);
struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, unsigned int ss_vendor,
unsigned int ss_device, struct pci_dev *from);
unsigned int num_gpib_events(const struct gpib_event_queue *queue);
int push_gpib_event(struct gpib_board *board, short event_type);
int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type);
int gpib_request_pseudo_irq(struct gpib_board *board, irqreturn_t (*handler)(int, void *));
void gpib_free_pseudo_irq(struct gpib_board *board);
int gpib_match_device_path(struct device *dev, const char *device_path_in);
extern struct gpib_board board_array[GPIB_MAX_NUM_BOARDS];
extern struct list_head registered_drivers;
#endif // _GPIB_P_H
+112
View File
@@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _GPIB_CMD_H
#define _GPIB_CMD_H
#include <linux/types.h>
/* Command byte definitions tests and functions */
/* mask of bits that actually matter in a command byte */
enum {
gpib_command_mask = 0x7f,
};
/* Possible GPIB command messages */
enum cmd_byte {
GTL = 0x1, /* go to local */
SDC = 0x4, /* selected device clear */
PP_CONFIG = 0x5,
GET = 0x8, /* group execute trigger */
TCT = 0x9, /* take control */
LLO = 0x11, /* local lockout */
DCL = 0x14, /* device clear */
PPU = 0x15, /* parallel poll unconfigure */
SPE = 0x18, /* serial poll enable */
SPD = 0x19, /* serial poll disable */
CFE = 0x1f, /* configure enable */
LAD = 0x20, /* value to be 'ored' in to obtain listen address */
UNL = 0x3F, /* unlisten */
TAD = 0x40, /* value to be 'ored' in to obtain talk address */
UNT = 0x5F, /* untalk */
SAD = 0x60, /* my secondary address (base) */
PPE = 0x60, /* parallel poll enable (base) */
PPD = 0x70 /* parallel poll disable */
};
/* confine address to range 0 to 30. */
static inline unsigned int gpib_address_restrict(u32 addr)
{
addr &= 0x1f;
if (addr == 0x1f)
addr = 0;
return addr;
}
static inline u8 MLA(u32 addr)
{
return gpib_address_restrict(addr) | LAD;
}
static inline u8 MTA(u32 addr)
{
return gpib_address_restrict(addr) | TAD;
}
static inline u8 MSA(u32 addr)
{
return (addr & 0x1f) | SAD;
}
static inline s32 gpib_address_equal(u32 pad1, s32 sad1, u32 pad2, s32 sad2)
{
if (pad1 == pad2) {
if (sad1 == sad2)
return 1;
if (sad1 < 0 && sad2 < 0)
return 1;
}
return 0;
}
static inline s32 is_PPE(u8 command)
{
return (command & 0x70) == 0x60;
}
static inline s32 is_PPD(u8 command)
{
return (command & 0x70) == 0x70;
}
static inline s32 in_addressed_command_group(u8 command)
{
return (command & 0x70) == 0x0;
}
static inline s32 in_universal_command_group(u8 command)
{
return (command & 0x70) == 0x10;
}
static inline s32 in_listen_address_group(u8 command)
{
return (command & 0x60) == 0x20;
}
static inline s32 in_talk_address_group(u8 command)
{
return (command & 0x60) == 0x40;
}
static inline s32 in_primary_command_group(u8 command)
{
return in_addressed_command_group(command) ||
in_universal_command_group(command) ||
in_listen_address_group(command) ||
in_talk_address_group(command);
}
#endif /* _GPIB_CMD_H */
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __GPIB_PCI_IDS_H
#define __GPIB_PCI_IDS_H
#ifndef PCI_VENDOR_ID_AMCC
#define PCI_VENDOR_ID_AMCC 0x10e8
#endif
#ifndef PCI_VENDOR_ID_CBOARDS
#define PCI_VENDOR_ID_CBOARDS 0x1307
#endif
#ifndef PCI_VENDOR_ID_QUANCOM
#define PCI_VENDOR_ID_QUANCOM 0x8008
#endif
#ifndef PCI_DEVICE_ID_QUANCOM_GPIB
#define PCI_DEVICE_ID_QUANCOM_GPIB 0x3302
#endif
#endif // __GPIB_PCI_IDS_H
@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef GPIB_PROTO_INCLUDED
#define GPIB_PROTO_INCLUDED
#include <linux/fs.h>
int ibopen(struct inode *inode, struct file *filep);
int ibclose(struct inode *inode, struct file *file);
long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg);
void os_start_timer(struct gpib_board *board, unsigned int usec_timeout);
void os_remove_timer(struct gpib_board *board);
void init_gpib_board(struct gpib_board *board);
static inline unsigned long usec_to_jiffies(unsigned int usec)
{
unsigned long usec_per_jiffy = 1000000 / HZ;
return 1 + (usec + usec_per_jiffy - 1) / usec_per_jiffy;
};
int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout);
void init_gpib_descriptor(struct gpib_descriptor *desc);
int dvrsp(struct gpib_board *board, unsigned int pad, int sad,
unsigned int usec_timeout, u8 *result);
int ibcac(struct gpib_board *board, int sync, int fallback_to_async);
int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written);
int ibgts(struct gpib_board *board);
int ibonline(struct gpib_board *board);
int iboffline(struct gpib_board *board);
int iblines(const struct gpib_board *board, short *lines);
int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *bytes_read);
int ibrpp(struct gpib_board *board, u8 *buf);
int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service);
int ibrsc(struct gpib_board *board, int request_control);
int ibsic(struct gpib_board *board, unsigned int usec_duration);
int ibsre(struct gpib_board *board, int enable);
int ibpad(struct gpib_board *board, unsigned int addr);
int ibsad(struct gpib_board *board, int addr);
int ibeos(struct gpib_board *board, int eos, int eosflags);
int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask,
int *status, unsigned long usec_timeout, struct gpib_descriptor *desc);
int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written);
int ibstatus(struct gpib_board *board);
int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device,
int clear_mask, int set_mask, struct gpib_descriptor *desc);
int io_timed_out(struct gpib_board *board);
int ibppc(struct gpib_board *board, u8 configuration);
#endif /* GPIB_PROTO_INCLUDED */
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2006 by Frank Mori Hess
***************************************************************************/
#ifndef _GPIB_STATE_MACHINES_H
#define _GPIB_STATE_MACHINES_H
enum talker_function_state {
talker_idle,
talker_addressed,
talker_active,
serial_poll_active
};
enum listener_function_state {
listener_idle,
listener_addressed,
listener_active
};
#endif // _GPIB_STATE_MACHINES_H
@@ -0,0 +1,389 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _GPIB_TYPES_H
#define _GPIB_TYPES_H
#ifdef __KERNEL__
#include <linux/gpib.h>
#include <linux/atomic.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
struct gpib_board;
/* config parameters that are only used by driver attach functions */
struct gpib_board_config {
/* firmware blob */
void *init_data;
int init_data_length;
/* IO base address to use for non-pnp cards (set by core, driver should make local copy) */
u32 ibbase;
void __iomem *mmibbase;
/* IRQ to use for non-pnp cards (set by core, driver should make local copy) */
unsigned int ibirq;
/* dma channel to use for non-pnp cards (set by core, driver should make local copy) */
unsigned int ibdma;
/*
* pci bus of card, useful for distinguishing multiple identical pci cards
* (negative means don't care)
*/
int pci_bus;
/*
* pci slot of card, useful for distinguishing multiple identical pci cards
* (negative means don't care)
*/
int pci_slot;
/* sysfs device path of hardware to attach */
char *device_path;
/* serial number of hardware to attach */
char *serial_number;
};
/*
* struct gpib_interface defines the interface
* between the board-specific details dealt with in the drivers
* and generic interface provided by gpib-common.
* This really should be in a different header file.
*/
struct gpib_interface {
/* name of board */
char *name;
/* attach() initializes board and allocates resources */
int (*attach)(struct gpib_board *board, const struct gpib_board_config *config);
/* detach() shuts down board and frees resources */
void (*detach)(struct gpib_board *board);
/*
* read() should read at most 'length' bytes from the bus into
* 'buffer'. It should return when it fills the buffer or
* encounters an END (EOI and or EOS if appropriate). It should set 'end'
* to be nonzero if the read was terminated by an END, otherwise 'end'
* should be zero.
* Ultimately, this will be changed into or replaced by an asynchronous
* read. Zero return value for success, negative
* return indicates error.
* nbytes returns number of bytes read
*/
int (*read)(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read);
/*
* write() should write 'length' bytes from buffer to the bus.
* If the boolean value send_eoi is nonzero, then EOI should
* be sent along with the last byte. Returns number of bytes
* written or negative value on error.
*/
int (*write)(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written);
/*
* command() writes the command bytes in 'buffer' to the bus
* Returns zero on success or negative value on error.
*/
int (*command)(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written);
/*
* Take control (assert ATN). If 'asyncronous' is nonzero, take
* control asyncronously (assert ATN immediately without waiting
* for other processes to complete first). Should not return
* until board becomes controller in charge. Returns zero no success,
* nonzero on error.
*/
int (*take_control)(struct gpib_board *board, int asyncronous);
/*
* De-assert ATN. Returns zero on success, nonzer on error.
*/
int (*go_to_standby)(struct gpib_board *board);
/* request/release control of the IFC and REN lines (system controller) */
int (*request_system_control)(struct gpib_board *board, int request_control);
/*
* Asserts or de-asserts 'interface clear' (IFC) depending on
* boolean value of 'assert'
*/
void (*interface_clear)(struct gpib_board *board, int assert);
/*
* Sends remote enable command if 'enable' is nonzero, disables remote mode
* if 'enable' is zero
*/
void (*remote_enable)(struct gpib_board *board, int enable);
/*
* enable END for reads, when byte 'eos' is received. If
* 'compare_8_bits' is nonzero, then all 8 bits are compared
* with the eos bytes. Otherwise only the 7 least significant
* bits are compared.
*/
int (*enable_eos)(struct gpib_board *board, u8 eos, int compare_8_bits);
/* disable END on eos byte (END on EOI only)*/
void (*disable_eos)(struct gpib_board *board);
/* configure parallel poll */
void (*parallel_poll_configure)(struct gpib_board *board, u8 configuration);
/* conduct parallel poll */
int (*parallel_poll)(struct gpib_board *board, u8 *result);
/* set/clear ist (individual status bit) */
void (*parallel_poll_response)(struct gpib_board *board, int ist);
/* select local parallel poll configuration mode PP2 versus remote PP1 */
void (*local_parallel_poll_mode)(struct gpib_board *board, int local);
/*
* Returns current status of the bus lines. Should be set to
* NULL if your board does not have the ability to query the
* state of the bus lines.
*/
int (*line_status)(const struct gpib_board *board);
/*
* updates and returns the board's current status.
* The meaning of the bits are specified in gpib_user.h
* in the IBSTA section. The driver does not need to
* worry about setting the CMPL, END, TIMO, or ERR bits.
*/
unsigned int (*update_status)(struct gpib_board *board, unsigned int clear_mask);
/*
* Sets primary address 0-30 for gpib interface card.
*/
int (*primary_address)(struct gpib_board *board, unsigned int address);
/*
* Sets and enables, or disables secondary address 0-30
* for gpib interface card.
*/
int (*secondary_address)(struct gpib_board *board, unsigned int address,
int enable);
/*
* Sets the byte the board should send in response to a serial poll.
* This function should also start or stop requests for service via
* IEEE 488.2 reqt/reqf, based on MSS (bit 6 of the status_byte).
* If the more flexible serial_poll_response2 is implemented by the
* driver, then this method should be left NULL since it will not
* be used. This method can generate spurious service requests
* which are allowed by IEEE 488.2, but not ideal.
*
* This method should implement the serial poll response method described
* by IEEE 488.2 section 11.3.3.4.3 "Allowed Coupled Control of
* STB, reqt, and reqf".
*/
void (*serial_poll_response)(struct gpib_board *board, u8 status_byte);
/*
* Sets the byte the board should send in response to a serial poll.
* This function should also request service via IEEE 488.2 reqt/reqf
* based on MSS (bit 6 of the status_byte) and new_reason_for_service.
* reqt should be set true if new_reason_for_service is true,
* and reqf should be set true if MSS is false. This function
* will never be called with MSS false and new_reason_for_service
* true simultaneously, so don't worry about that case.
*
* This method implements the serial poll response method described
* by IEEE 488.2 section 11.3.3.4.1 "Preferred Implementation".
*
* If this method is left NULL by the driver, then the user library
* function ibrsv2 will not work.
*/
void (*serial_poll_response2)(struct gpib_board *board, u8 status_byte,
int new_reason_for_service);
/*
* returns the byte the board will send in response to a serial poll.
*/
u8 (*serial_poll_status)(struct gpib_board *board);
/* adjust T1 delay */
int (*t1_delay)(struct gpib_board *board, unsigned int nano_sec);
/* go to local mode */
void (*return_to_local)(struct gpib_board *board);
/* board does not support 7 bit eos comparisons */
unsigned no_7_bit_eos : 1;
/* skip check for listeners before trying to send command bytes */
unsigned skip_check_for_command_acceptors : 1;
};
struct gpib_event_queue {
struct list_head event_head;
spinlock_t lock; // for access to event list
unsigned int num_events;
unsigned dropped_event : 1;
};
static inline void init_event_queue(struct gpib_event_queue *queue)
{
INIT_LIST_HEAD(&queue->event_head);
queue->num_events = 0;
queue->dropped_event = 0;
spin_lock_init(&queue->lock);
}
/* struct for supporting polling operation when irq is not available */
struct gpib_pseudo_irq {
struct timer_list timer;
irqreturn_t (*handler)(int irq, void *arg);
struct gpib_board *board;
atomic_t active;
};
static inline void init_gpib_pseudo_irq(struct gpib_pseudo_irq *pseudo_irq)
{
pseudo_irq->handler = NULL;
timer_setup(&pseudo_irq->timer, NULL, 0);
atomic_set(&pseudo_irq->active, 0);
}
/* list so we can make a linked list of drivers */
struct gpib_interface_list {
struct list_head list;
struct gpib_interface *interface;
struct module *module;
};
/*
* One struct gpib_board is allocated for each physical board in the computer.
* It provides storage for variables local to each board, and interface
* functions for performing operations on the board
*/
struct gpib_board {
/* functions used by this board */
struct gpib_interface *interface;
/*
* Pointer to module whose use count we should increment when
* interface is in use
*/
struct module *provider_module;
/* buffer used to store read/write data for this board */
u8 *buffer;
/* length of buffer */
unsigned int buffer_length;
/*
* Used to hold the board's current status (see update_status() above)
*/
unsigned long status;
/*
* Driver should only sleep on this wait queue. It is special in that the
* core will wake this queue and set the TIMO bit in 'status' when the
* watchdog timer times out.
*/
wait_queue_head_t wait;
/*
* Lock that only allows one process to access this board at a time.
* Has to be first in any locking order, since it can be locked over
* multiple ioctls.
*/
struct mutex user_mutex;
/*
* Mutex which compensates for removal of "big kernel lock" from kernel.
* Should not be held for extended waits.
*/
struct mutex big_gpib_mutex;
/* pid of last process to lock the board mutex */
pid_t locking_pid;
/* lock for setting locking pid */
spinlock_t locking_pid_spinlock;
/* Spin lock for dealing with races with the interrupt handler */
spinlock_t spinlock;
/* Watchdog timer to enable timeouts */
struct timer_list timer;
/* device of attached driver if any */
struct device *dev;
/* gpib_common device gpibN */
struct device *gpib_dev;
/*
* 'private_data' can be used as seen fit by the driver to
* store additional variables for this board
*/
void *private_data;
/* Number of open file descriptors using this board */
unsigned int use_count;
/* list of open devices connected to this board */
struct list_head device_list;
/* primary address */
unsigned int pad;
/* secondary address */
int sad;
/* timeout for io operations, in microseconds */
unsigned int usec_timeout;
/* board's parallel poll configuration byte */
u8 parallel_poll_configuration;
/* t1 delay we are using */
unsigned int t1_nano_sec;
/* Count that keeps track of whether board is up and running or not */
unsigned int online;
/* number of processes trying to autopoll */
int autospollers;
/* autospoll kernel thread */
struct task_struct *autospoll_task;
/* queue for recording received trigger/clear/ifc events */
struct gpib_event_queue event_queue;
/* minor number for this board's device file */
int minor;
/* struct to deal with polling mode*/
struct gpib_pseudo_irq pseudo_irq;
/* error dong autopoll */
atomic_t stuck_srq;
struct gpib_board_config config;
/* Flag that indicates whether board is system controller of the bus */
unsigned master : 1;
/* individual status bit */
unsigned ist : 1;
/*
* one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0),
* zero means remote parallel poll configuration mode ieee 488.1 PP1
*/
unsigned local_ppoll_mode : 1;
};
/* element of event queue */
struct gpib_event {
struct list_head list;
short event_type;
};
/*
* Each board has a list of gpib_status_queue to keep track of all open devices
* on the bus, so we know what address to poll when we get a service request
*/
struct gpib_status_queue {
/* list_head so we can make a linked list of devices */
struct list_head list;
unsigned int pad; /* primary gpib address */
int sad; /* secondary gpib address (negative means disabled) */
/* stores serial poll bytes for this device */
struct list_head status_bytes;
unsigned int num_status_bytes;
/* number of times this address is opened */
unsigned int reference_count;
/* flags loss of status byte error due to limit on size of queue */
unsigned dropped_byte : 1;
};
struct gpib_status_byte {
struct list_head list;
u8 poll_byte;
};
void init_gpib_status_queue(struct gpib_status_queue *device);
/* Used to store device-descriptor-specific information */
struct gpib_descriptor {
unsigned int pad; /* primary gpib address */
int sad; /* secondary gpib address (negative means disabled) */
atomic_t io_in_progress;
/*
* Kernel-only reference count to prevent descriptor from being
* freed while IO handlers hold a pointer to it. Incremented
* before each IO operation, decremented when done. Unlike
* io_in_progress, this cannot be modified from userspace via
* general_ibstatus().
*/
atomic_t descriptor_busy;
unsigned is_board : 1;
unsigned autopoll_enabled : 1;
};
struct gpib_file_private {
atomic_t holding_mutex;
struct gpib_descriptor *descriptors[GPIB_MAX_NUM_DESCRIPTORS];
/* locked while descriptors are being allocated/deallocated */
struct mutex descriptors_mutex;
unsigned got_module : 1;
};
#endif /* __KERNEL__ */
#endif /* _GPIB_TYPES_H */
+141
View File
@@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _NEC7210_H
#define _NEC7210_H
#include "gpib_state_machines.h"
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include "gpib_types.h"
#include "nec7210_registers.h"
/* struct used to provide variables local to a nec7210 chip */
struct nec7210_priv {
#ifdef CONFIG_HAS_IOPORT
u32 iobase;
#endif
void __iomem *mmiobase;
unsigned int offset; // offset between successive nec7210 io addresses
unsigned int dma_channel;
u8 *dma_buffer;
unsigned int dma_buffer_length; // length of dma buffer
dma_addr_t dma_buffer_addr; // bus address of board->buffer for use with dma
// software copy of bits written to registers
u8 reg_bits[8];
u8 auxa_bits; // bits written to auxiliary register A
u8 auxb_bits; // bits written to auxiliary register B
// used to keep track of board's state, bit definitions given below
unsigned long state;
// lock for chips that extend the nec7210 registers by paging in alternate regs
spinlock_t register_page_lock;
// wrappers for outb, inb, readb, or writeb
u8 (*read_byte)(struct nec7210_priv *priv, unsigned int register_number);
void (*write_byte)(struct nec7210_priv *priv, u8 byte, unsigned int register_number);
enum nec7210_chipset type;
enum talker_function_state talker_state;
enum listener_function_state listener_state;
void *private;
unsigned srq_pending : 1;
};
static inline void init_nec7210_private(struct nec7210_priv *priv)
{
memset(priv, 0, sizeof(struct nec7210_priv));
spin_lock_init(&priv->register_page_lock);
}
// slightly shorter way to access read_byte and write_byte
static inline u8 read_byte(struct nec7210_priv *priv, unsigned int register_number)
{
return priv->read_byte(priv, register_number);
}
static inline void write_byte(struct nec7210_priv *priv, u8 byte, unsigned int register_number)
{
priv->write_byte(priv, byte, register_number);
}
// struct nec7210_priv.state bit numbers
enum {
PIO_IN_PROGRESS_BN, // pio transfer in progress
DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress
DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress
READ_READY_BN, // board has data byte available to read
WRITE_READY_BN, // board is ready to send a data byte
COMMAND_READY_BN, // board is ready to send a command byte
RECEIVED_END_BN, // received END
BUS_ERROR_BN, // output error has occurred
RFD_HOLDOFF_BN, // rfd holdoff in effect
DEV_CLEAR_BN, // device clear received
ADR_CHANGE_BN, // address state change occurred
};
// interface functions
int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read);
int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written);
int nec7210_take_control(struct gpib_board *board, struct nec7210_priv *priv, int syncronous);
int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv);
int nec7210_request_system_control(struct gpib_board *board,
struct nec7210_priv *priv, int request_control);
void nec7210_interface_clear(struct gpib_board *board, struct nec7210_priv *priv, int assert);
void nec7210_remote_enable(struct gpib_board *board, struct nec7210_priv *priv, int enable);
int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_bytes,
int compare_8_bits);
void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv);
unsigned int nec7210_update_status(struct gpib_board *board, struct nec7210_priv *priv,
unsigned int clear_mask);
unsigned int nec7210_update_status_nolock(struct gpib_board *board, struct nec7210_priv *priv);
int nec7210_primary_address(const struct gpib_board *board,
struct nec7210_priv *priv, unsigned int address);
int nec7210_secondary_address(const struct gpib_board *board, struct nec7210_priv *priv,
unsigned int address, int enable);
int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result);
void nec7210_serial_poll_response(struct gpib_board *board,
struct nec7210_priv *priv, u8 status);
void nec7210_parallel_poll_configure(struct gpib_board *board,
struct nec7210_priv *priv, unsigned int configuration);
void nec7210_parallel_poll_response(struct gpib_board *board,
struct nec7210_priv *priv, int ist);
u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv);
int nec7210_t1_delay(struct gpib_board *board,
struct nec7210_priv *priv, unsigned int nano_sec);
void nec7210_return_to_local(const struct gpib_board *board, struct nec7210_priv *priv);
// utility functions
void nec7210_board_reset(struct nec7210_priv *priv, const struct gpib_board *board);
void nec7210_board_online(struct nec7210_priv *priv, const struct gpib_board *board);
unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg,
unsigned int mask, unsigned int bits);
void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *priv, int mode);
void nec7210_release_rfd_holdoff(struct gpib_board *board, struct nec7210_priv *priv);
u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end);
// wrappers for io functions
u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num);
u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num);
u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num);
u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num);
// interrupt service routine
irqreturn_t nec7210_interrupt(struct gpib_board *board, struct nec7210_priv *priv);
irqreturn_t nec7210_interrupt_have_status(struct gpib_board *board,
struct nec7210_priv *priv, int status1, int status2);
#endif //_NEC7210_H
@@ -0,0 +1,218 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _NEC7210_REGISTERS_H
#define _NEC7210_REGISTERS_H
enum nec7210_chipset {
NEC7210, // The original
TNT4882, // NI
NAT4882, // NI
CB7210, // measurement computing
IOT7210, // iotech
IGPIB7210, // Ines
TNT5004, // NI (minor differences to TNT4882)
};
/*
* nec7210 register numbers (might need to be multiplied by
* a board-dependent offset to get actually io address offset)
*/
// write registers
enum nec7210_write_regs {
CDOR, // command/data out
IMR1, // interrupt mask 1
IMR2, // interrupt mask 2
SPMR, // serial poll mode
ADMR, // address mode
AUXMR, // auxiliary mode
ADR, // address
EOSR, // end-of-string
// nec7210 has 8 registers
nec7210_num_registers = 8,
};
// read registers
enum nec7210_read_regs {
DIR, // data in
ISR1, // interrupt status 1
ISR2, // interrupt status 2
SPSR, // serial poll status
ADSR, // address status
CPTR, // command pass though
ADR0, // address 1
ADR1, // address 2
};
// bit definitions common to nec-7210 compatible registers
// ISR1: interrupt status register 1
enum isr1_bits {
HR_DI = (1 << 0),
HR_DO = (1 << 1),
HR_ERR = (1 << 2),
HR_DEC = (1 << 3),
HR_END = (1 << 4),
HR_DET = (1 << 5),
HR_APT = (1 << 6),
HR_CPT = (1 << 7),
};
// IMR1: interrupt mask register 1
enum imr1_bits {
HR_DIIE = (1 << 0),
HR_DOIE = (1 << 1),
HR_ERRIE = (1 << 2),
HR_DECIE = (1 << 3),
HR_ENDIE = (1 << 4),
HR_DETIE = (1 << 5),
HR_APTIE = (1 << 6),
HR_CPTIE = (1 << 7),
};
// ISR2, interrupt status register 2
enum isr2_bits {
HR_ADSC = (1 << 0),
HR_REMC = (1 << 1),
HR_LOKC = (1 << 2),
HR_CO = (1 << 3),
HR_REM = (1 << 4),
HR_LOK = (1 << 5),
HR_SRQI = (1 << 6),
HR_INT = (1 << 7),
};
// IMR2, interrupt mask register 2
enum imr2_bits {
// all the bits in this register that enable interrupts
IMR2_ENABLE_INTR_MASK = 0x4f,
HR_ACIE = (1 << 0),
HR_REMIE = (1 << 1),
HR_LOKIE = (1 << 2),
HR_COIE = (1 << 3),
HR_DMAI = (1 << 4),
HR_DMAO = (1 << 5),
HR_SRQIE = (1 << 6),
};
// SPSR, serial poll status register
enum spsr_bits {
HR_PEND = (1 << 6),
};
// SPMR, serial poll mode register
enum spmr_bits {
HR_RSV = (1 << 6),
};
// ADSR, address status register
enum adsr_bits {
HR_MJMN = (1 << 0),
HR_TA = (1 << 1),
HR_LA = (1 << 2),
HR_TPAS = (1 << 3),
HR_LPAS = (1 << 4),
HR_SPMS = (1 << 5),
HR_NATN = (1 << 6),
HR_CIC = (1 << 7),
};
// ADMR, address mode register
enum admr_bits {
HR_ADM0 = (1 << 0),
HR_ADM1 = (1 << 1),
HR_TRM0 = (1 << 4),
HR_TRM1 = (1 << 5),
HR_TRM_EOIOE_TRIG = 0,
HR_TRM_CIC_TRIG = HR_TRM0,
HR_TRM_CIC_EOIOE = HR_TRM1,
HR_TRM_CIC_PE = HR_TRM0 | HR_TRM1,
HR_LON = (1 << 6),
HR_TON = (1 << 7),
};
// ADR, bits used in address0, address1 and address0/1 registers
enum adr_bits {
ADDRESS_MASK = 0x1f, /* mask to specify lower 5 bits */
HR_DL = (1 << 5),
HR_DT = (1 << 6),
HR_ARS = (1 << 7),
};
// ADR1, address1 register
enum adr1_bits {
HR_EOI = (1 << 7),
};
// AUXMR, auxiliary mode register
enum auxmr_bits {
ICR = 0x20,
PPR = 0x60,
AUXRA = 0x80,
AUXRB = 0xa0,
AUXRE = 0xc0,
};
// auxra, auxiliary register A
enum auxra_bits {
HR_HANDSHAKE_MASK = 0x3,
HR_HLDA = 0x1,
HR_HLDE = 0x2,
HR_LCM = 0x3, /* auxra listen continuous */
HR_REOS = 0x4,
HR_XEOS = 0x8,
HR_BIN = 0x10,
};
// auxrb, auxiliary register B
enum auxrb_bits {
HR_CPTE = (1 << 0),
HR_SPEOI = (1 << 1),
HR_TRI = (1 << 2),
HR_INV = (1 << 3),
HR_ISS = (1 << 4),
};
enum auxre_bits {
HR_DAC_HLD_DCAS = 0x1, /* perform DAC holdoff on receiving clear */
HR_DAC_HLD_DTAS = 0x2, /* perform DAC holdoff on receiving trigger */
};
// parallel poll register
enum ppr_bits {
HR_PPS = (1 << 3),
HR_PPU = (1 << 4),
};
/* 7210 Auxiliary Commands */
enum aux_cmds {
AUX_PON = 0x0, /* Immediate Execute pon */
AUX_CPPF = 0x1, /* Clear Parallel Poll Flag */
AUX_CR = 0x2, /* Chip Reset */
AUX_FH = 0x3, /* Finish Handshake */
AUX_TRIG = 0x4, /* Trigger */
AUX_RTL = 0x5, /* Return to local */
AUX_SEOI = 0x6, /* Send EOI */
AUX_NVAL = 0x7, /* Non-Valid Secondary Command or Address */
AUX_SPPF = 0x9, /* Set Parallel Poll Flag */
AUX_VAL = 0xf, /* Valid Secondary Command or Address */
AUX_GTS = 0x10, /* Go To Standby */
AUX_TCA = 0x11, /* Take Control Asynchronously */
AUX_TCS = 0x12, /* Take Control Synchronously */
AUX_LTN = 0x13, /* Listen */
AUX_DSC = 0x14, /* Disable System Control */
AUX_CIFC = 0x16, /* Clear IFC */
AUX_CREN = 0x17, /* Clear REN */
AUX_TCSE = 0x1a, /* Take Control Synchronously on End */
AUX_LTNC = 0x1b, /* Listen in Continuous Mode */
AUX_LUN = 0x1c, /* Local Unlisten */
AUX_EPP = 0x1d, /* Execute Parallel Poll */
AUX_SIFC = 0x1e, /* Set IFC */
AUX_SREN = 0x1f, /* Set REN */
};
#endif //_NEC7210_REGISTERS_H
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Header for plx9050 pci chip
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _PLX9050_GPIB_H
#define _PLX9050_GPIB_H
// plx pci chip registers and bits
enum {
PLX9050_INTCSR_REG = 0x4c,
PLX9050_CNTRL_REG = 0x50
};
enum plx9050_intcsr_bits {
PLX9050_LINTR1_EN_BIT = 0x1,
PLX9050_LINTR1_POLARITY_BIT = 0x2,
PLX9050_LINTR1_STATUS_BIT = 0x4,
PLX9050_LINTR2_EN_BIT = 0x8,
PLX9050_LINTR2_POLARITY_BIT = 0x10,
PLX9050_LINTR2_STATUS_BIT = 0x20,
PLX9050_PCI_INTR_EN_BIT = 0x40,
PLX9050_SOFT_INTR_BIT = 0x80,
PLX9050_LINTR1_SELECT_ENABLE_BIT = 0x100, // 9052 extension
PLX9050_LINTR2_SELECT_ENABLE_BIT = 0x200, // 9052 extension
PLX9050_LINTR1_EDGE_CLEAR_BIT = 0x400, // 9052 extension
PLX9050_LINTR2_EDGE_CLEAR_BIT = 0x800, // 9052 extension
};
enum plx9050_cntrl_bits {
PLX9050_WAITO_NOT_USER0_SELECT_BIT = 0x1,
PLX9050_USER0_OUTPUT_BIT = 0x2,
PLX9050_USER0_DATA_BIT = 0x4,
PLX9050_LLOCK_NOT_USER1_SELECT_BIT = 0x8,
PLX9050_USER1_OUTPUT_BIT = 0x10,
PLX9050_USER1_DATA_BIT = 0x20,
PLX9050_CS2_NOT_USER2_SELECT_BIT = 0x40,
PLX9050_USER2_OUTPUT_BIT = 0x80,
PLX9050_USER2_DATA_BIT = 0x100,
PLX9050_CS3_NOT_USER3_SELECT_BIT = 0x200,
PLX9050_USER3_OUTPUT_BIT = 0x400,
PLX9050_USER3_DATA_BIT = 0x800,
PLX9050_PCIBAR_ENABLE_MASK = 0x3000,
PLX9050_PCIBAR_MEMORY_AND_IO_ENABLE_BITS = 0x0,
PLX9050_PCIBAR_MEMORY_NO_IO_ENABLE_BITS = 0x1000,
PLX9050_PCIBAR_IO_NO_MEMORY_ENABLE_BITS = 0x2000,
PLX9050_PCIBAR_MEMORY_AND_IO_TOO_ENABLE_BITS = 0x3000,
PLX9050_PCI_READ_MODE_BIT = 0x4000,
PLX9050_PCI_READ_WITH_WRITE_FLUSH_MODE_BIT = 0x8000,
PLX9050_PCI_READ_NO_FLUSH_MODE_BIT = 0x10000,
PLX9050_PCI_READ_NO_WRITE_MODE_BIT = 0x20000,
PLX9050_PCI_WRITE_MODE_BIT = 0x40000,
PLX9050_PCI_RETRY_DELAY_MASK = 0x780000,
PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT = 0x800000,
PLX9050_EEPROM_CLOCK_BIT = 0x1000000,
PLX9050_EEPROM_CHIP_SELECT_BIT = 0x2000000,
PLX9050_WRITE_TO_EEPROM_BIT = 0x4000000,
PLX9050_READ_EEPROM_DATA_BIT = 0x8000000,
PLX9050_EEPROM_VALID_BIT = 0x10000000,
PLX9050_RELOAD_CONFIG_REGISTERS_BIT = 0x20000000,
PLX9050_PCI_SOFTWARE_RESET_BIT = 0x40000000,
PLX9050_MASK_REVISION_BIT = 0x80000000
};
static inline unsigned int PLX9050_PCI_RETRY_DELAY_BITS(unsigned int clocks)
{
return ((clocks / 8) << 19) & PLX9050_PCI_RETRY_DELAY_MASK;
}
#endif // _PLX9050_GPIB_H
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Quancom pci stuff
* copyright (C) 2005 by Frank Mori Hess
***************************************************************************/
#ifndef _QUANCOM_PCI_H
#define _QUANCOM_PCI_H
/* quancom registers */
enum quancom_regs {
QUANCOM_IRQ_CONTROL_STATUS_REG = 0xfc,
};
enum quancom_irq_control_status_bits {
QUANCOM_IRQ_ASSERTED_BIT = 0x1, /* readable */
/* (any write to the register clears the interrupt)*/
QUANCOM_IRQ_ENABLE_BIT = 0x4, /* writeable */
};
#endif // _QUANCOM_PCI_H
+280
View File
@@ -0,0 +1,280 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _TMS9914_H
#define _TMS9914_H
#include <linux/types.h>
#include <linux/interrupt.h>
#include "gpib_state_machines.h"
#include "gpib_types.h"
enum tms9914_holdoff_mode {
TMS9914_HOLDOFF_NONE,
TMS9914_HOLDOFF_EOI,
TMS9914_HOLDOFF_ALL,
};
/* struct used to provide variables local to a tms9914 chip */
struct tms9914_priv {
#ifdef CONFIG_HAS_IOPORT
u32 iobase;
#endif
void __iomem *mmiobase;
unsigned int offset; // offset between successive tms9914 io addresses
unsigned int dma_channel;
// software copy of bits written to interrupt mask registers
u8 imr0_bits, imr1_bits;
// bits written to address mode register
u8 admr_bits;
u8 auxa_bits; // bits written to auxiliary register A
// used to keep track of board's state, bit definitions given below
unsigned long state;
u8 eos; // eos character
short eos_flags;
u8 spoll_status;
enum tms9914_holdoff_mode holdoff_mode;
unsigned int ppoll_line;
enum talker_function_state talker_state;
enum listener_function_state listener_state;
unsigned ppoll_sense : 1;
unsigned ppoll_enable : 1;
unsigned ppoll_configure_state : 1;
unsigned primary_listen_addressed : 1;
unsigned primary_talk_addressed : 1;
unsigned holdoff_on_end : 1;
unsigned holdoff_on_all : 1;
unsigned holdoff_active : 1;
// wrappers for outb, inb, readb, or writeb
u8 (*read_byte)(struct tms9914_priv *priv, unsigned int register_number);
void (*write_byte)(struct tms9914_priv *priv, u8 byte, unsigned int
register_number);
};
// slightly shorter way to access read_byte and write_byte
static inline u8 read_byte(struct tms9914_priv *priv, unsigned int register_number)
{
return priv->read_byte(priv, register_number);
}
static inline void write_byte(struct tms9914_priv *priv, u8 byte, unsigned int register_number)
{
priv->write_byte(priv, byte, register_number);
}
// struct tms9914_priv.state bit numbers
enum {
PIO_IN_PROGRESS_BN, // pio transfer in progress
DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress
DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress
READ_READY_BN, // board has data byte available to read
WRITE_READY_BN, // board is ready to send a data byte
COMMAND_READY_BN, // board is ready to send a command byte
RECEIVED_END_BN, // received END
BUS_ERROR_BN, // bus error
DEV_CLEAR_BN, // device clear received
};
// interface functions
int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read);
int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written);
int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, int syncronous);
/*
* alternate version of tms9914_take_control which works around buggy tcs
* implementation.
*/
int tms9914_take_control_workaround(struct gpib_board *board, struct tms9914_priv *priv,
int syncronous);
int tms9914_go_to_standby(struct gpib_board *board, struct tms9914_priv *priv);
int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
int request_control);
void tms9914_interface_clear(struct gpib_board *board, struct tms9914_priv *priv, int assert);
void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv, int enable);
int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_bytes,
int compare_8_bits);
void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv);
unsigned int tms9914_update_status(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int clear_mask);
int tms9914_primary_address(struct gpib_board *board,
struct tms9914_priv *priv, unsigned int address);
int tms9914_secondary_address(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int address, int enable);
int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result);
void tms9914_parallel_poll_configure(struct gpib_board *board,
struct tms9914_priv *priv, u8 config);
void tms9914_parallel_poll_response(struct gpib_board *board,
struct tms9914_priv *priv, int ist);
void tms9914_serial_poll_response(struct gpib_board *board,
struct tms9914_priv *priv, u8 status);
u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv);
int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *priv);
unsigned int tms9914_t1_delay(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int nano_sec);
void tms9914_return_to_local(const struct gpib_board *board, struct tms9914_priv *priv);
// utility functions
void tms9914_board_reset(struct tms9914_priv *priv);
void tms9914_online(struct gpib_board *board, struct tms9914_priv *priv);
void tms9914_release_holdoff(struct tms9914_priv *priv);
void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode);
// wrappers for io functions
u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num);
void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num);
u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num);
void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num);
// interrupt service routine
irqreturn_t tms9914_interrupt(struct gpib_board *board, struct tms9914_priv *priv);
irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms9914_priv *priv,
int status1, int status2);
// tms9914 has 8 registers
enum {
ms9914_num_registers = 8,
};
/*
* tms9914 register numbers (might need to be multiplied by
* a board-dependent offset to get actually io address offset)
*/
// write registers
enum {
IMR0 = 0, /* interrupt mask 0 */
IMR1 = 1, /* interrupt mask 1 */
AUXCR = 3, /* auxiliary command */
ADR = 4, /* address register */
SPMR = 5, /* serial poll mode register */
PPR = 6, /* parallel poll */
CDOR = 7, /* data out register */
};
// read registers
enum {
ISR0 = 0, /* interrupt status 0 */
ISR1 = 1, /* interrupt status 1 */
ADSR = 2, /* address status */
BSR = 3, /* bus status */
CPTR = 6, /* command pass thru */
DIR = 7, /* data in register */
};
// bit definitions common to tms9914 compatible registers
/* ISR0 - Register bits */
enum isr0_bits {
HR_MAC = (1 << 0), /* My Address Change */
HR_RLC = (1 << 1), /* Remote/Local change */
HR_SPAS = (1 << 2), /* Serial Poll active State */
HR_END = (1 << 3), /* END (EOI or EOS) */
HR_BO = (1 << 4), /* Byte Out */
HR_BI = (1 << 5), /* Byte In */
};
/* IMR0 - Register bits */
enum imr0_bits {
HR_MACIE = (1 << 0), /* */
HR_RLCIE = (1 << 1), /* */
HR_SPASIE = (1 << 2), /* */
HR_ENDIE = (1 << 3), /* */
HR_BOIE = (1 << 4), /* */
HR_BIIE = (1 << 5), /* */
};
/* ISR1 - Register bits */
enum isr1_bits {
HR_IFC = (1 << 0), /* IFC asserted */
HR_SRQ = (1 << 1), /* SRQ asserted */
HR_MA = (1 << 2), /* My Address */
HR_DCAS = (1 << 3), /* Device Clear active State */
HR_APT = (1 << 4), /* Address pass Through */
HR_UNC = (1 << 5), /* Unrecognized Command */
HR_ERR = (1 << 6), /* Data Transmission Error */
HR_GET = (1 << 7), /* Group execute Trigger */
};
/* IMR1 - Register bits */
enum imr1_bits {
HR_IFCIE = (1 << 0), /* */
HR_SRQIE = (1 << 1), /* */
HR_MAIE = (1 << 2), /* */
HR_DCASIE = (1 << 3), /* */
HR_APTIE = (1 << 4), /* */
HR_UNCIE = (1 << 5), /* */
HR_ERRIE = (1 << 6), /* */
HR_GETIE = (1 << 7), /* */
};
/* ADSR - Register bits */
enum adsr_bits {
HR_ULPA = (1 << 0), /* Store last address LSB */
HR_TA = (1 << 1), /* Talker Adressed */
HR_LA = (1 << 2), /* Listener adressed */
HR_TPAS = (1 << 3), /* talker primary address state */
HR_LPAS = (1 << 4), /* listener " */
HR_ATN = (1 << 5), /* ATN active */
HR_LLO = (1 << 6), /* LLO active */
HR_REM = (1 << 7), /* REM active */
};
/* ADR - Register bits */
enum adr_bits {
ADDRESS_MASK = 0x1f, /* mask to specify lower 5 bits for ADR */
HR_DAT = (1 << 5), /* disable talker */
HR_DAL = (1 << 6), /* disable listener */
HR_EDPA = (1 << 7), /* enable dual primary addressing */
};
enum bus_status_bits {
BSR_REN_BIT = 0x1,
BSR_IFC_BIT = 0x2,
BSR_SRQ_BIT = 0x4,
BSR_EOI_BIT = 0x8,
BSR_NRFD_BIT = 0x10,
BSR_NDAC_BIT = 0x20,
BSR_DAV_BIT = 0x40,
BSR_ATN_BIT = 0x80,
};
/*---------------------------------------------------------*/
/* TMS 9914 Auxiliary Commands */
/*---------------------------------------------------------*/
enum aux_cmd_bits {
AUX_CS = 0x80, /* set bit instead of clearing it, used with commands marked 'd' below */
AUX_CHIP_RESET = 0x0, /* d Chip reset */
AUX_INVAL = 0x1, /* release dac holdoff, invalid command byte */
AUX_VAL = (AUX_INVAL | AUX_CS), /* release dac holdoff, valid command byte */
AUX_RHDF = 0x2, /* X Release RFD holdoff */
AUX_HLDA = 0x3, /* d holdoff on all data */
AUX_HLDE = 0x4, /* d holdoff on EOI only */
AUX_NBAF = 0x5, /* X Set new byte available false */
AUX_FGET = 0x6, /* d force GET */
AUX_RTL = 0x7, /* d return to local */
AUX_SEOI = 0x8, /* X send EOI with next byte */
AUX_LON = 0x9, /* d Listen only */
AUX_TON = 0xa, /* d Talk only */
AUX_GTS = 0xb, /* X goto standby */
AUX_TCA = 0xc, /* X take control asynchronously */
AUX_TCS = 0xd, /* X take " synchronously */
AUX_RPP = 0xe, /* d Request parallel poll */
AUX_SIC = 0xf, /* d send interface clear */
AUX_SRE = 0x10, /* d send remote enable */
AUX_RQC = 0x11, /* X request control */
AUX_RLC = 0x12, /* X release control */
AUX_DAI = 0x13, /* d disable all interrupts */
AUX_PTS = 0x14, /* X pass through next secondary */
AUX_STDL = 0x15, /* d short T1 delay */
AUX_SHDW = 0x16, /* d shadow handshake */
AUX_VSTDL = 0x17, /* d very short T1 delay (smj9914 extension) */
AUX_RSV2 = 0x18, /* d request service bit 2 (smj9914 extension) */
};
#endif //_TMS9914_H
@@ -0,0 +1,192 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002, 2004 by Frank Mori Hess
***************************************************************************/
#ifndef _TNT4882_REGISTERS_H
#define _TNT4882_REGISTERS_H
// tnt4882 register offsets
enum {
ACCWR = 0x5,
// offset of auxiliary command register in 9914 mode
AUXCR = 0x6,
INTRT = 0x7,
// register number for auxiliary command register when swap bit is set (9914 mode)
SWAPPED_AUXCR = 0xa,
HSSEL = 0xd, // handshake select register
CNT2 = 0x9,
CNT3 = 0xb,
CFG = 0x10,
SASR = 0x1b,
IMR0 = 0x1d,
IMR3 = 0x12,
CNT0 = 0x14,
CNT1 = 0x16,
KEYREG = 0x17, // key control register (7210 mode only)
CSR = KEYREG,
FIFOB = 0x18,
FIFOA = 0x19,
CCR = 0x1a, // carry cycle register
CMDR = 0x1c, // command register
TIMER = 0x1e, // timer register
STS1 = 0x10, // T488 Status Register 1
STS2 = 0x1c, // T488 Status Register 2
ISR0 = IMR0,
ISR3 = 0x1a, // T488 Interrupt Status Register 3
BCR = 0x1f, // bus control/status register
BSR = BCR,
};
enum {
tnt_pagein_offset = 0x11,
};
/*============================================================*/
/* TURBO-488 registers bit definitions */
enum bus_control_status_bits {
BCSR_REN_BIT = 0x1,
BCSR_IFC_BIT = 0x2,
BCSR_SRQ_BIT = 0x4,
BCSR_EOI_BIT = 0x8,
BCSR_NRFD_BIT = 0x10,
BCSR_NDAC_BIT = 0x20,
BCSR_DAV_BIT = 0x40,
BCSR_ATN_BIT = 0x80,
};
/* CFG -- Configuration Register (write only) */
enum cfg_bits {
TNT_COMMAND = 0x80, /* bytes are command bytes instead of data bytes
* (tnt4882 one-chip and newer only?)
*/
TNT_TLCHE = (1 << 6), /* halt transfer on imr0, imr1, or imr2 interrupt */
TNT_IN = (1 << 5), /* transfer is GPIB read */
TNT_A_B = (1 << 4), /* order to use fifos 1=fifo A first(big endian),
* 0=fifo b first(little endian)
*/
TNT_CCEN = (1 << 3), /* enable carry cycle */
TNT_TMOE = (1 << 2), /* enable CPU bus time limit */
TNT_TIM_BYTN = (1 << 1), /* tmot reg is: 1=125ns clocks, 0=num bytes */
TNT_B_16BIT = (1 << 0), /* 1=FIFO is 16-bit register, 0=8-bit */
};
/* CMDR -- Command Register */
enum cmdr_bits {
CLRSC = 0x2, /* clear the system controller bit */
SETSC = 0x3, /* set the system controller bit */
GO = 0x4, /* start fifos */
STOP = 0x8, /* stop fifos */
RESET_FIFO = 0x10, /* reset the FIFOs */
SOFT_RESET = 0x22, /* issue a software reset */
HARD_RESET = 0x40 /* 500x only? */
};
/* HSSEL -- handshake select register (write only) */
enum hssel_bits {
TNT_ONE_CHIP_BIT = 0x1,
NODMA = 0x10,
TNT_GO2SIDS_BIT = 0x20,
};
/* IMR0 -- Interrupt Mode Register 0 */
enum imr0_bits {
TNT_SYNCIE_BIT = 0x1, /* handshake sync */
TNT_TOIE_BIT = 0x2, /* timeout */
TNT_ATNIE_BIT = 0x4, /* ATN interrupt */
TNT_IFCIE_BIT = 0x8, /* interface clear interrupt */
TNT_BTO_BIT = 0x10, /* byte timeout */
TNT_NLEN_BIT = 0x20, /* treat new line as EOS char */
TNT_STBOIE_BIT = 0x40, /* status byte out */
TNT_IMR0_ALWAYS_BITS = 0x80, /* always set this bit on write */
};
/* ISR0 -- Interrupt Status Register 0 */
enum isr0_bits {
TNT_SYNC_BIT = 0x1, /* handshake sync */
TNT_TO_BIT = 0x2, /* timeout */
TNT_ATNI_BIT = 0x4, /* ATN interrupt */
TNT_IFCI_BIT = 0x8, /* interface clear interrupt */
TNT_EOS_BIT = 0x10, /* end of string */
TNT_NL_BIT = 0x20, /* new line receive */
TNT_STBO_BIT = 0x40, /* status byte out */
TNT_NBA_BIT = 0x80, /* new byte available */
};
/* ISR3 -- Interrupt Status Register 3 (read only) */
enum isr3_bits {
HR_DONE = (1 << 0), /* transfer done */
HR_TLCI = (1 << 1), /* isr0, isr1, or isr2 interrupt asserted */
HR_NEF = (1 << 2), /* NOT empty fifo */
HR_NFF = (1 << 3), /* NOT full fifo */
HR_STOP = (1 << 4), /* fifo empty or STOP command issued */
HR_SRQI_CIC = (1 << 5), /* SRQ asserted and we are CIC (500x only?)*/
HR_INTR = (1 << 7), /* isr3 interrupt active */
};
enum keyreg_bits {
MSTD = 0x20, /* enable 350ns T1 delay */
};
/* STS1 -- Status Register 1 (read only) */
enum sts1_bits {
S_DONE = 0x80, /* DMA done */
S_SC = 0x40, /* is system controller */
S_IN = 0x20, /* DMA in (to memory) */
S_DRQ = 0x10, /* DRQ line (for diagnostics) */
S_STOP = 0x08, /* DMA stopped */
S_NDAV = 0x04, /* inverse of DAV */
S_HALT = 0x02, /* status of transfer machine */
S_GSYNC = 0x01, /* indicates if GPIB is in sync w I/O */
};
/* STS2 -- Status Register 2 */
enum sts2_bits {
AFFN = (1 << 3), /* "A full FIFO NOT" (0=FIFO full) */
AEFN = (1 << 2), /* "A empty FIFO NOT" (0=FIFO empty) */
BFFN = (1 << 1), /* "B full FIFO NOT" (0=FIFO full) */
BEFN = (1 << 0), /* "B empty FIFO NOT" (0=FIFO empty) */
};
// Auxiliary commands
enum tnt4882_aux_cmds {
AUX_9914 = 0x15, // switch to 9914 mode
AUX_REQT = 0x18,
AUX_REQF = 0x19,
AUX_PAGEIN = 0x50, // page in alternate registers
AUX_HLDI = 0x51, // rfd holdoff immediately
AUX_CLEAR_END = 0x55,
AUX_7210 = 0x99, // switch to 7210 mode
};
enum tnt4882_aux_regs {
AUXRG = 0x40,
AUXRI = 0xe0,
};
enum auxg_bits {
/* no talking when no listeners bit (prevents bus errors when data written at wrong time) */
NTNL_BIT = 0x8,
RPP2_BIT = 0x4, /* set/clear local rpp message */
CHES_BIT = 0x1, /*clear holdoff on end select bit*/
};
enum auxi_bits {
SISB = 0x1, // static interrupt bits (don't clear isr1, isr2 on read)
PP2 = 0x4, // ignore remote parallel poll configuration
USTD = 0x8, // ultra short (1100 nanosec) T1 delay
};
enum sasr_bits {
ACRDY_BIT = 0x4, /* acceptor ready state */
ADHS_BIT = 0x8, /* acceptor data holdoff state */
ANHS2_BIT = 0x10, /* acceptor not ready holdoff immediately state */
ANHS1_BIT = 0x20, /* acceptor not ready holdoff state */
AEHS_BIT = 0x40, /* acceptor end holdoff state */
};
#endif // _TNT4882_REGISTERS_H
+3
View File
@@ -0,0 +1,3 @@
obj-$(CONFIG_GPIB_INES) += ines_gpib.o
+181
View File
@@ -0,0 +1,181 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* Header for ines GPIB boards
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _INES_GPIB_H
#define _INES_GPIB_H
#include "nec7210.h"
#include "gpibP.h"
#include "plx9050.h"
#include "amcc5920.h"
#include "quancom_pci.h"
#include <linux/interrupt.h>
enum ines_pci_chip {
PCI_CHIP_NONE,
PCI_CHIP_PLX9050,
PCI_CHIP_AMCC5920,
PCI_CHIP_QUANCOM,
PCI_CHIP_QUICKLOGIC5030,
PCI_CHIP_INES_72130,
};
struct ines_priv {
struct nec7210_priv nec7210_priv;
struct pci_dev *pci_device;
// base address for plx9052 pci chip
unsigned long plx_iobase;
// base address for amcc5920 pci chip
unsigned long amcc_iobase;
unsigned int irq;
enum ines_pci_chip pci_chip_type;
u8 extend_mode_bits;
};
/* inb/outb wrappers */
static inline unsigned int ines_inb(struct ines_priv *priv, unsigned int register_number)
{
return inb(priv->nec7210_priv.iobase +
register_number * priv->nec7210_priv.offset);
}
static inline void ines_outb(struct ines_priv *priv, unsigned int value,
unsigned int register_number)
{
outb(value, priv->nec7210_priv.iobase +
register_number * priv->nec7210_priv.offset);
}
enum ines_regs {
// read
FIFO_STATUS = 0x8,
ISR3 = 0x9,
ISR4 = 0xa,
IN_FIFO_COUNT = 0x10,
OUT_FIFO_COUNT = 0x11,
EXTEND_STATUS = 0xf,
// write
XDMA_CONTROL = 0x8,
IMR3 = ISR3,
IMR4 = ISR4,
IN_FIFO_WATERMARK = IN_FIFO_COUNT,
OUT_FIFO_WATERMARK = OUT_FIFO_COUNT,
EXTEND_MODE = 0xf,
// read-write
XFER_COUNT_LOWER = 0xb,
XFER_COUNT_UPPER = 0xc,
BUS_CONTROL_MONITOR = 0x13,
};
enum isr3_imr3_bits {
HW_TIMEOUT_BIT = 0x1,
XFER_COUNT_BIT = 0x2,
CMD_RECEIVED_BIT = 0x4,
TCT_RECEIVED_BIT = 0x8,
IFC_ACTIVE_BIT = 0x10,
ATN_ACTIVE_BIT = 0x20,
FIFO_ERROR_BIT = 0x40,
};
enum isr4_imr4_bits {
IN_FIFO_WATERMARK_BIT = 0x1,
OUT_FIFO_WATERMARK_BIT = 0x2,
IN_FIFO_FULL_BIT = 0x4,
OUT_FIFO_EMPTY_BIT = 0x8,
IN_FIFO_READY_BIT = 0x10,
OUT_FIFO_READY_BIT = 0x20,
IN_FIFO_EXIT_WATERMARK_BIT = 0x40,
OUT_FIFO_EXIT_WATERMARK_BIT = 0x80,
};
enum extend_mode_bits {
TR3_TRIG_ENABLE_BIT = 0x1, // enable generation of trigger pulse T/R3 pin
// clear message available status bit when chip writes byte with EOI true
MAV_ENABLE_BIT = 0x2,
EOS1_ENABLE_BIT = 0x4, // enable eos register 1
EOS2_ENABLE_BIT = 0x8, // enable eos register 2
EOIDIS_BIT = 0x10, // disable EOI interrupt when doing rfd holdoff on end?
XFER_COUNTER_ENABLE_BIT = 0x20,
XFER_COUNTER_OUTPUT_BIT = 0x40, // use counter for output, clear for input
// when xfer counter hits 0, assert EOI on write or RFD holdoff on read
LAST_BYTE_HANDLING_BIT = 0x80,
};
enum extend_status_bits {
OUTPUT_MESSAGE_IN_PROGRESS_BIT = 0x1,
SCSEL_BIT = 0x2, // statue of SCSEL pin
LISTEN_DISABLED = 0x4,
IN_FIFO_EMPTY_BIT = 0x8,
OUT_FIFO_FULL_BIT = 0x10,
};
// ines adds fifo enable bits to address mode register
enum ines_admr_bits {
IN_FIFO_ENABLE_BIT = 0x8,
OUT_FIFO_ENABLE_BIT = 0x4,
};
enum xdma_control_bits {
DMA_OUTPUT_BIT = 0x1, // use dma for output, clear for input
ENABLE_SYNC_DMA_BIT = 0x2,
DMA_ACCESS_EVERY_CYCLE = 0x4, // dma accesses fifo every cycle, clear for every other cycle
DMA_16BIT = 0x8, // clear for 8 bit transfers
};
enum bus_control_monitor_bits {
BCM_DAV_BIT = 0x1,
BCM_NRFD_BIT = 0x2,
BCM_NDAC_BIT = 0x4,
BCM_IFC_BIT = 0x8,
BCM_ATN_BIT = 0x10,
BCM_SRQ_BIT = 0x20,
BCM_REN_BIT = 0x40,
BCM_EOI_BIT = 0x80,
};
enum ines_aux_reg_bits {
INES_AUXD = 0x40,
};
enum ines_aux_cmds {
INES_RFD_HLD_IMMEDIATE = 0x4,
INES_AUX_CLR_OUT_FIFO = 0x5,
INES_AUX_CLR_IN_FIFO = 0x6,
INES_AUX_XMODE = 0xa,
};
enum ines_auxd_bits {
INES_FOLLOWING_T1_MASK = 0x3,
INES_FOLLOWING_T1_500ns = 0x0,
INES_FOLLOWING_T1_350ns = 0x1,
INES_FOLLOWING_T1_250ns = 0x2,
INES_INITIAL_TI_MASK = 0xc,
INES_INITIAL_T1_2000ns = 0x0,
INES_INITIAL_T1_1100ns = 0x4,
INES_INITIAL_T1_700ns = 0x8,
INES_T6_2us = 0x0,
INES_T6_50us = 0x10,
};
enum ines72130_regs {
BUS_STATUS_REG = 0xc,
};
enum ines_72130_bus_status_bits {
BSR_NRFD_BIT = 0x1,
BSR_NDAC_BIT = 0x2,
BSR_DAV_BIT = 0x4,
BSR_EOI_BIT = 0x8,
BSR_SRQ_BIT = 0x10,
BSR_ATN_BIT = 0x20,
BSR_REN_BIT = 0x40,
BSR_IFC_BIT = 0x80,
};
#endif // _INES_GPIB_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
obj-$(CONFIG_GPIB_LPVO) += lpvo_usb_gpib.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
obj-$(CONFIG_GPIB_NEC7210) += nec7210.o
+19
View File
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2001, 2002 by Frank Mori Hess
***************************************************************************/
#ifndef _GPIB_PCIIA_BOARD_H
#define _GPIB_PCIIA_BOARD_H
#include "gpibP.h"
#include <linux/io.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include "nec7210.h"
#endif //_GPIB_PCIIA_BOARD_H
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
obj-$(CONFIG_GPIB_NI_USB) += ni_usb_gpib.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,226 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2004 by Frank Mori Hess
***************************************************************************/
#ifndef _NI_USB_GPIB_H
#define _NI_USB_GPIB_H
#include <linux/mutex.h>
#include <linux/semaphore.h>
#include <linux/usb.h>
#include <linux/timer.h>
#include "gpibP.h"
enum {
USB_VENDOR_ID_NI = 0x3923
};
enum {
USB_DEVICE_ID_NI_USB_B = 0x702a,
USB_DEVICE_ID_NI_USB_B_PREINIT = 0x702b, // device id before firmware is loaded
USB_DEVICE_ID_NI_USB_HS = 0x709b,
USB_DEVICE_ID_NI_USB_HS_PLUS = 0x7618,
USB_DEVICE_ID_KUSB_488A = 0x725c,
USB_DEVICE_ID_MC_USB_488 = 0x725d
};
enum ni_usb_device {
NIUSB_SUBDEV_TNT4882 = 1,
NIUSB_SUBDEV_UNKNOWN2 = 2,
NIUSB_SUBDEV_UNKNOWN3 = 3,
};
enum endpoint_addresses {
NIUSB_B_BULK_OUT_ENDPOINT = 0x2,
NIUSB_B_BULK_IN_ENDPOINT = 0x2,
NIUSB_B_BULK_IN_ALT_ENDPOINT = 0x6,
NIUSB_B_INTERRUPT_IN_ENDPOINT = 0x4,
};
enum hs_enpoint_addresses {
NIUSB_HS_BULK_OUT_ENDPOINT = 0x2,
NIUSB_HS_BULK_OUT_ALT_ENDPOINT = 0x6,
NIUSB_HS_BULK_IN_ENDPOINT = 0x4,
NIUSB_HS_BULK_IN_ALT_ENDPOINT = 0x8,
NIUSB_HS_INTERRUPT_IN_ENDPOINT = 0x1,
};
enum hs_plus_endpoint_addresses {
NIUSB_HS_PLUS_BULK_OUT_ENDPOINT = 0x1,
NIUSB_HS_PLUS_BULK_OUT_ALT_ENDPOINT = 0x4,
NIUSB_HS_PLUS_BULK_IN_ENDPOINT = 0x2,
NIUSB_HS_PLUS_BULK_IN_ALT_ENDPOINT = 0x5,
NIUSB_HS_PLUS_INTERRUPT_IN_ENDPOINT = 0x3,
};
struct ni_usb_urb_ctx {
struct completion complete;
unsigned timed_out : 1;
};
// struct which defines private_data for ni_usb devices
struct ni_usb_priv {
struct usb_interface *bus_interface;
int bulk_out_endpoint;
int bulk_in_endpoint;
int interrupt_in_endpoint;
u8 eos_char;
unsigned short eos_mode;
unsigned int monitored_ibsta_bits;
struct urb *bulk_urb;
struct urb *interrupt_urb;
u8 interrupt_buffer[0x11];
struct mutex addressed_transfer_lock; // protect transfer lock
struct mutex bulk_transfer_lock; // protect bulk message sends
struct mutex control_transfer_lock; // protect control messages
struct mutex interrupt_transfer_lock; // protect interrupt messages
struct timer_list bulk_timer;
struct ni_usb_urb_ctx context;
int product_id;
unsigned short ren_state;
};
struct ni_usb_status_block {
short id;
unsigned short ibsta;
short error_code;
unsigned short count;
};
struct ni_usb_register {
enum ni_usb_device device;
short address;
unsigned short value;
};
enum ni_usb_bulk_ids {
NIUSB_IBCAC_ID = 0x1,
NIUSB_UNKNOWN3_ID = 0x3, // device level function id?
NIUSB_TERM_ID = 0x4,
NIUSB_IBGTS_ID = 0x6,
NIUSB_IBRPP_ID = 0x7,
NIUSB_REG_READ_ID = 0x8,
NIUSB_REG_WRITE_ID = 0x9,
NIUSB_IBSIC_ID = 0xf,
NIUSB_REGISTER_READ_DATA_START_ID = 0x34,
NIUSB_REGISTER_READ_DATA_END_ID = 0x35,
NIUSB_IBRD_DATA_ID = 0x36,
NIUSB_IBRD_EXTENDED_DATA_ID = 0x37,
NIUSB_IBRD_STATUS_ID = 0x38
};
enum ni_usb_error_codes {
NIUSB_NO_ERROR = 0,
/*
* NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by
* doing a NI_USB_STOP_REQUEST on the control endpoint.
*/
NIUSB_ABORTED_ERROR = 1,
/*
* NIUSB_READ_ATN_ERROR occurs when you do a board read while
* ATN is set
*/
NIUSB_ATN_STATE_ERROR = 2,
/*
* NIUSB_ADDRESSING_ERROR occurs when you do a board
* read/write as CIC but are not in LACS/TACS
*/
NIUSB_ADDRESSING_ERROR = 3,
/*
* NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char
* bits are set when REOS is not set.
* Have also seen error 4 if you try to send more than 16
* command bytes at once on a usb-b.
*/
NIUSB_EOSMODE_ERROR = 4,
/*
* NIUSB_NO_BUS_ERROR occurs when you try to write a command
* byte but there are no devices connected to the gpib bus
*/
NIUSB_NO_BUS_ERROR = 5,
/*
* NIUSB_NO_LISTENER_ERROR occurs when you do a board write as
* CIC with no listener
*/
NIUSB_NO_LISTENER_ERROR = 8,
/* get NIUSB_TIMEOUT_ERROR on board read/write timeout */
NIUSB_TIMEOUT_ERROR = 10,
};
enum ni_usb_control_requests {
NI_USB_STOP_REQUEST = 0x20,
NI_USB_WAIT_REQUEST = 0x21,
NI_USB_POLL_READY_REQUEST = 0x40,
NI_USB_SERIAL_NUMBER_REQUEST = 0x41,
NI_USB_HS_PLUS_0x48_REQUEST = 0x48,
NI_USB_HS_PLUS_LED_REQUEST = 0x4b,
NI_USB_HS_PLUS_0xf8_REQUEST = 0xf8
};
static const unsigned int ni_usb_ibsta_monitor_mask =
SRQI | LOK | REM | CIC | ATN | TACS | LACS | DTAS | DCAS;
static inline int nec7210_to_tnt4882_offset(int offset)
{
return 2 * offset;
};
static inline int ni_usb_bulk_termination(u8 *buffer)
{
int i = 0;
buffer[i++] = NIUSB_TERM_ID;
buffer[i++] = 0x0;
buffer[i++] = 0x0;
buffer[i++] = 0x0;
return i;
}
enum ni_usb_unknown3_register {
SERIAL_NUMBER_4_REG = 0x8,
SERIAL_NUMBER_3_REG = 0x9,
SERIAL_NUMBER_2_REG = 0xa,
SERIAL_NUMBER_1_REG = 0xb,
};
static inline int ni_usb_bulk_register_write_header(u8 *buffer, int num_writes)
{
int i = 0;
buffer[i++] = NIUSB_REG_WRITE_ID;
buffer[i++] = num_writes;
buffer[i++] = 0x0;
return i;
}
static inline int ni_usb_bulk_register_write(u8 *buffer, struct ni_usb_register reg)
{
int i = 0;
buffer[i++] = reg.device;
buffer[i++] = reg.address;
buffer[i++] = reg.value;
return i;
}
static inline int ni_usb_bulk_register_read_header(u8 *buffer, int num_reads)
{
int i = 0;
buffer[i++] = NIUSB_REG_READ_ID;
buffer[i++] = num_reads;
return i;
}
static inline int ni_usb_bulk_register_read(u8 *buffer, int device, int address)
{
int i = 0;
buffer[i++] = device;
buffer[i++] = address;
return i;
}
#endif // _NI_USB_GPIB_H
+5
View File
@@ -0,0 +1,5 @@
obj-$(CONFIG_GPIB_PC2) += pc2_gpib.o
+685
View File
@@ -0,0 +1,685 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2001, 2002 by Frank Mori Hess
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/string.h>
#include <linux/init.h>
#include "nec7210.h"
#include "gpibP.h"
// struct which defines private_data for pc2 driver
struct pc2_priv {
struct nec7210_priv nec7210_priv;
unsigned int irq;
// io address that clears interrupt for pc2a (0x2f0 + irq)
unsigned int clear_intr_addr;
};
// pc2 uses 8 consecutive io addresses
static const int pc2_iosize = 8;
static const int pc2a_iosize = 8;
static const int pc2_2a_iosize = 16;
// offset between io addresses of successive nec7210 registers
static const int pc2a_reg_offset = 0x400;
static const int pc2_reg_offset = 1;
// interrupt service routine
static irqreturn_t pc2_interrupt(int irq, void *arg);
static irqreturn_t pc2a_interrupt(int irq, void *arg);
// pc2 specific registers and bits
// interrupt clear register address
static const int pc2a_clear_intr_iobase = 0x2f0;
static inline unsigned int CLEAR_INTR_REG(unsigned int irq)
{
return pc2a_clear_intr_iobase + irq;
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for PC2/PC2a and compatible devices");
/*
* GPIB interrupt service routines
*/
irqreturn_t pc2_interrupt(int irq, void *arg)
{
struct gpib_board *board = arg;
struct pc2_priv *priv = board->private_data;
unsigned long flags;
irqreturn_t retval;
spin_lock_irqsave(&board->spinlock, flags);
retval = nec7210_interrupt(board, &priv->nec7210_priv);
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
irqreturn_t pc2a_interrupt(int irq, void *arg)
{
struct gpib_board *board = arg;
struct pc2_priv *priv = board->private_data;
int status1, status2;
unsigned long flags;
irqreturn_t retval;
spin_lock_irqsave(&board->spinlock, flags);
// read interrupt status (also clears status)
status1 = read_byte(&priv->nec7210_priv, ISR1);
status2 = read_byte(&priv->nec7210_priv, ISR2);
/* clear interrupt circuit */
if (priv->irq)
outb(0xff, CLEAR_INTR_REG(priv->irq));
retval = nec7210_interrupt_have_status(board, &priv->nec7210_priv, status1, status2);
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
// wrappers for interface functions
static int pc2_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct pc2_priv *priv = board->private_data;
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
static int pc2_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct pc2_priv *priv = board->private_data;
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
static int pc2_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct pc2_priv *priv = board->private_data;
return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written);
}
static int pc2_take_control(struct gpib_board *board, int synchronous)
{
struct pc2_priv *priv = board->private_data;
return nec7210_take_control(board, &priv->nec7210_priv, synchronous);
}
static int pc2_go_to_standby(struct gpib_board *board)
{
struct pc2_priv *priv = board->private_data;
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
static int pc2_request_system_control(struct gpib_board *board, int request_control)
{
struct pc2_priv *priv = board->private_data;
return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
}
static void pc2_interface_clear(struct gpib_board *board, int assert)
{
struct pc2_priv *priv = board->private_data;
nec7210_interface_clear(board, &priv->nec7210_priv, assert);
}
static void pc2_remote_enable(struct gpib_board *board, int enable)
{
struct pc2_priv *priv = board->private_data;
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
static int pc2_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct pc2_priv *priv = board->private_data;
return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits);
}
static void pc2_disable_eos(struct gpib_board *board)
{
struct pc2_priv *priv = board->private_data;
nec7210_disable_eos(board, &priv->nec7210_priv);
}
static unsigned int pc2_update_status(struct gpib_board *board, unsigned int clear_mask)
{
struct pc2_priv *priv = board->private_data;
return nec7210_update_status(board, &priv->nec7210_priv, clear_mask);
}
static int pc2_primary_address(struct gpib_board *board, unsigned int address)
{
struct pc2_priv *priv = board->private_data;
return nec7210_primary_address(board, &priv->nec7210_priv, address);
}
static int pc2_secondary_address(struct gpib_board *board, unsigned int address, int enable)
{
struct pc2_priv *priv = board->private_data;
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
static int pc2_parallel_poll(struct gpib_board *board, u8 *result)
{
struct pc2_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
static void pc2_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct pc2_priv *priv = board->private_data;
nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config);
}
static void pc2_parallel_poll_response(struct gpib_board *board, int ist)
{
struct pc2_priv *priv = board->private_data;
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
static void pc2_serial_poll_response(struct gpib_board *board, u8 status)
{
struct pc2_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
static u8 pc2_serial_poll_status(struct gpib_board *board)
{
struct pc2_priv *priv = board->private_data;
return nec7210_serial_poll_status(board, &priv->nec7210_priv);
}
static int pc2_t1_delay(struct gpib_board *board, unsigned int nano_sec)
{
struct pc2_priv *priv = board->private_data;
return nec7210_t1_delay(board, &priv->nec7210_priv, nano_sec);
}
static void pc2_return_to_local(struct gpib_board *board)
{
struct pc2_priv *priv = board->private_data;
nec7210_return_to_local(board, &priv->nec7210_priv);
}
static int allocate_private(struct gpib_board *board)
{
struct pc2_priv *priv;
board->private_data = kzalloc_obj(struct pc2_priv);
if (!board->private_data)
return -ENOMEM;
priv = board->private_data;
init_nec7210_private(&priv->nec7210_priv);
return 0;
}
static void free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
static int pc2_generic_attach(struct gpib_board *board, const struct gpib_board_config *config,
enum nec7210_chipset chipset)
{
struct pc2_priv *pc2_priv;
struct nec7210_priv *nec_priv;
int retval;
board->status = 0;
retval = allocate_private(board);
if (retval)
return retval;
pc2_priv = board->private_data;
nec_priv = &pc2_priv->nec7210_priv;
nec_priv->read_byte = nec7210_ioport_read_byte;
nec_priv->write_byte = nec7210_ioport_write_byte;
nec_priv->type = chipset;
#ifndef PC2_DMA
/*
* board->dev hasn't been initialized, so forget about DMA until this driver
* is adapted to use isa_register_driver.
*/
if (config->ibdma)
// driver needs to be adapted to use isa_register_driver to get a struct device*
dev_err(board->gpib_dev, "DMA disabled for pc2 gpib");
#else
if (config->ibdma) {
nec_priv->dma_buffer_length = 0x1000;
nec_priv->dma_buffer = dma_alloc_coherent(board->dev,
nec_priv->dma_buffer_length, &
nec_priv->dma_buffer_addr, GFP_ATOMIC);
if (!nec_priv->dma_buffer)
return -ENOMEM;
// request isa dma channel
if (request_dma(config->ibdma, "pc2")) {
dev_err(board->gpib_dev, "can't request DMA %d\n", config->ibdma);
return -1;
}
nec_priv->dma_channel = config->ibdma;
}
#endif
return 0;
}
static int pc2_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int isr_flags = 0;
struct pc2_priv *pc2_priv;
struct nec7210_priv *nec_priv;
int retval;
retval = pc2_generic_attach(board, config, NEC7210);
if (retval)
return retval;
pc2_priv = board->private_data;
nec_priv = &pc2_priv->nec7210_priv;
nec_priv->offset = pc2_reg_offset;
if (!request_region(config->ibbase, pc2_iosize, "pc2")) {
dev_err(board->gpib_dev, "ioports are already in use\n");
return -EBUSY;
}
nec_priv->iobase = config->ibbase;
nec7210_board_reset(nec_priv, board);
// install interrupt handler
if (config->ibirq) {
if (request_irq(config->ibirq, pc2_interrupt, isr_flags, "pc2", board)) {
dev_err(board->gpib_dev, "can't request IRQ %d\n", config->ibirq);
return -EBUSY;
}
}
pc2_priv->irq = config->ibirq;
/* poll so we can detect assertion of ATN */
if (gpib_request_pseudo_irq(board, pc2_interrupt)) {
dev_err(board->gpib_dev, "failed to allocate pseudo_irq\n");
return -1;
}
/* set internal counter register for 8 MHz input clock */
write_byte(nec_priv, ICR | 8, AUXMR);
nec7210_board_online(nec_priv, board);
return 0;
}
static void pc2_detach(struct gpib_board *board)
{
struct pc2_priv *pc2_priv = board->private_data;
struct nec7210_priv *nec_priv;
if (pc2_priv) {
nec_priv = &pc2_priv->nec7210_priv;
#ifdef PC2_DMA
if (nec_priv->dma_channel)
free_dma(nec_priv->dma_channel);
#endif
gpib_free_pseudo_irq(board);
if (pc2_priv->irq)
free_irq(pc2_priv->irq, board);
if (nec_priv->iobase) {
nec7210_board_reset(nec_priv, board);
release_region(nec_priv->iobase, pc2_iosize);
}
if (nec_priv->dma_buffer) {
dma_free_coherent(board->dev, nec_priv->dma_buffer_length,
nec_priv->dma_buffer, nec_priv->dma_buffer_addr);
nec_priv->dma_buffer = NULL;
}
}
free_private(board);
}
static int pc2a_common_attach(struct gpib_board *board, const struct gpib_board_config *config,
unsigned int num_registers, enum nec7210_chipset chipset)
{
unsigned int i, j;
struct pc2_priv *pc2_priv;
struct nec7210_priv *nec_priv;
int retval;
retval = pc2_generic_attach(board, config, chipset);
if (retval)
return retval;
pc2_priv = board->private_data;
nec_priv = &pc2_priv->nec7210_priv;
nec_priv->offset = pc2a_reg_offset;
switch (config->ibbase) {
case 0x02e1:
case 0x22e1:
case 0x42e1:
case 0x62e1:
break;
default:
dev_err(board->gpib_dev, "PCIIa base range invalid, must be one of 0x[0246]2e1, but is 0x%x\n",
config->ibbase);
return -1;
}
if (config->ibirq) {
if (config->ibirq < 2 || config->ibirq > 7) {
dev_err(board->gpib_dev, "illegal interrupt level %i\n",
config->ibirq);
return -1;
}
} else {
dev_err(board->gpib_dev, "interrupt disabled, using polling mode (slow)\n");
}
#ifdef CHECK_IOPORTS
unsigned int err = 0;
for (i = 0; i < num_registers; i++) {
if (check_region(config->ibbase + i * pc2a_reg_offset, 1))
err++;
}
if (config->ibirq && check_region(pc2a_clear_intr_iobase + config->ibirq, 1))
err++;
if (err) {
dev_err(board->gpib_dev, "ioports are already in use");
return -EBUSY;
}
#endif
for (i = 0; i < num_registers; i++) {
if (!request_region(config->ibbase +
i * pc2a_reg_offset, 1, "pc2a")) {
dev_err(board->gpib_dev, "ioports are already in use");
for (j = 0; j < i; j++)
release_region(config->ibbase +
j * pc2a_reg_offset, 1);
return -EBUSY;
}
}
nec_priv->iobase = config->ibbase;
if (config->ibirq) {
if (!request_region(pc2a_clear_intr_iobase + config->ibirq, 1, "pc2a")) {
dev_err(board->gpib_dev, "ioports are already in use");
return -1;
}
pc2_priv->clear_intr_addr = pc2a_clear_intr_iobase + config->ibirq;
if (request_irq(config->ibirq, pc2a_interrupt, 0, "pc2a", board)) {
dev_err(board->gpib_dev, "can't request IRQ %d\n", config->ibirq);
return -EBUSY;
}
}
pc2_priv->irq = config->ibirq;
/* poll so we can detect assertion of ATN */
if (gpib_request_pseudo_irq(board, pc2_interrupt)) {
dev_err(board->gpib_dev, "failed to allocate pseudo_irq\n");
return -1;
}
// make sure interrupt is clear
if (pc2_priv->irq)
outb(0xff, CLEAR_INTR_REG(pc2_priv->irq));
nec7210_board_reset(nec_priv, board);
/* set internal counter register for 8 MHz input clock */
write_byte(nec_priv, ICR | 8, AUXMR);
nec7210_board_online(nec_priv, board);
return 0;
}
static int pc2a_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2a_iosize, NEC7210);
}
static int pc2a_cb7210_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2a_iosize, CB7210);
}
static int pc2_2a_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2_2a_iosize, NAT4882);
}
static void pc2a_common_detach(struct gpib_board *board, unsigned int num_registers)
{
int i;
struct pc2_priv *pc2_priv = board->private_data;
struct nec7210_priv *nec_priv;
if (pc2_priv) {
nec_priv = &pc2_priv->nec7210_priv;
#ifdef PC2_DMA
if (nec_priv->dma_channel)
free_dma(nec_priv->dma_channel);
#endif
gpib_free_pseudo_irq(board);
if (pc2_priv->irq)
free_irq(pc2_priv->irq, board);
if (nec_priv->iobase) {
nec7210_board_reset(nec_priv, board);
for (i = 0; i < num_registers; i++)
release_region(nec_priv->iobase +
i * pc2a_reg_offset, 1);
}
if (pc2_priv->clear_intr_addr)
release_region(pc2_priv->clear_intr_addr, 1);
if (nec_priv->dma_buffer) {
dma_free_coherent(board->dev, nec_priv->dma_buffer_length,
nec_priv->dma_buffer,
nec_priv->dma_buffer_addr);
nec_priv->dma_buffer = NULL;
}
}
free_private(board);
}
static void pc2a_detach(struct gpib_board *board)
{
pc2a_common_detach(board, pc2a_iosize);
}
static void pc2_2a_detach(struct gpib_board *board)
{
pc2a_common_detach(board, pc2_2a_iosize);
}
static struct gpib_interface pc2_interface = {
.name = "pcII",
.attach = pc2_attach,
.detach = pc2_detach,
.read = pc2_read,
.write = pc2_write,
.command = pc2_command,
.take_control = pc2_take_control,
.go_to_standby = pc2_go_to_standby,
.request_system_control = pc2_request_system_control,
.interface_clear = pc2_interface_clear,
.remote_enable = pc2_remote_enable,
.enable_eos = pc2_enable_eos,
.disable_eos = pc2_disable_eos,
.parallel_poll = pc2_parallel_poll,
.parallel_poll_configure = pc2_parallel_poll_configure,
.parallel_poll_response = pc2_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = NULL,
.update_status = pc2_update_status,
.primary_address = pc2_primary_address,
.secondary_address = pc2_secondary_address,
.serial_poll_response = pc2_serial_poll_response,
.serial_poll_status = pc2_serial_poll_status,
.t1_delay = pc2_t1_delay,
.return_to_local = pc2_return_to_local,
};
static struct gpib_interface pc2a_interface = {
.name = "pcIIa",
.attach = pc2a_attach,
.detach = pc2a_detach,
.read = pc2_read,
.write = pc2_write,
.command = pc2_command,
.take_control = pc2_take_control,
.go_to_standby = pc2_go_to_standby,
.request_system_control = pc2_request_system_control,
.interface_clear = pc2_interface_clear,
.remote_enable = pc2_remote_enable,
.enable_eos = pc2_enable_eos,
.disable_eos = pc2_disable_eos,
.parallel_poll = pc2_parallel_poll,
.parallel_poll_configure = pc2_parallel_poll_configure,
.parallel_poll_response = pc2_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = NULL,
.update_status = pc2_update_status,
.primary_address = pc2_primary_address,
.secondary_address = pc2_secondary_address,
.serial_poll_response = pc2_serial_poll_response,
.serial_poll_status = pc2_serial_poll_status,
.t1_delay = pc2_t1_delay,
.return_to_local = pc2_return_to_local,
};
static struct gpib_interface pc2a_cb7210_interface = {
.name = "pcIIa_cb7210",
.attach = pc2a_cb7210_attach,
.detach = pc2a_detach,
.read = pc2_read,
.write = pc2_write,
.command = pc2_command,
.take_control = pc2_take_control,
.go_to_standby = pc2_go_to_standby,
.request_system_control = pc2_request_system_control,
.interface_clear = pc2_interface_clear,
.remote_enable = pc2_remote_enable,
.enable_eos = pc2_enable_eos,
.disable_eos = pc2_disable_eos,
.parallel_poll = pc2_parallel_poll,
.parallel_poll_configure = pc2_parallel_poll_configure,
.parallel_poll_response = pc2_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = NULL, // XXX
.update_status = pc2_update_status,
.primary_address = pc2_primary_address,
.secondary_address = pc2_secondary_address,
.serial_poll_response = pc2_serial_poll_response,
.serial_poll_status = pc2_serial_poll_status,
.t1_delay = pc2_t1_delay,
.return_to_local = pc2_return_to_local,
};
static struct gpib_interface pc2_2a_interface = {
.name = "pcII_IIa",
.attach = pc2_2a_attach,
.detach = pc2_2a_detach,
.read = pc2_read,
.write = pc2_write,
.command = pc2_command,
.take_control = pc2_take_control,
.go_to_standby = pc2_go_to_standby,
.request_system_control = pc2_request_system_control,
.interface_clear = pc2_interface_clear,
.remote_enable = pc2_remote_enable,
.enable_eos = pc2_enable_eos,
.disable_eos = pc2_disable_eos,
.parallel_poll = pc2_parallel_poll,
.parallel_poll_configure = pc2_parallel_poll_configure,
.parallel_poll_response = pc2_parallel_poll_response,
.local_parallel_poll_mode = NULL, // XXX
.line_status = NULL,
.update_status = pc2_update_status,
.primary_address = pc2_primary_address,
.secondary_address = pc2_secondary_address,
.serial_poll_response = pc2_serial_poll_response,
.serial_poll_status = pc2_serial_poll_status,
.t1_delay = pc2_t1_delay,
.return_to_local = pc2_return_to_local,
};
static int __init pc2_init_module(void)
{
int ret;
ret = gpib_register_driver(&pc2_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
return ret;
}
ret = gpib_register_driver(&pc2a_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
goto err_pc2a;
}
ret = gpib_register_driver(&pc2a_cb7210_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
goto err_cb7210;
}
ret = gpib_register_driver(&pc2_2a_interface, THIS_MODULE);
if (ret) {
pr_err("gpib_register_driver failed: error = %d\n", ret);
goto err_pc2_2a;
}
return 0;
err_pc2_2a:
gpib_unregister_driver(&pc2a_cb7210_interface);
err_cb7210:
gpib_unregister_driver(&pc2a_interface);
err_pc2a:
gpib_unregister_driver(&pc2_interface);
return ret;
}
static void __exit pc2_exit_module(void)
{
gpib_unregister_driver(&pc2_interface);
gpib_unregister_driver(&pc2a_interface);
gpib_unregister_driver(&pc2a_cb7210_interface);
gpib_unregister_driver(&pc2_2a_interface);
}
module_init(pc2_init_module);
module_exit(pc2_exit_module);
@@ -0,0 +1,6 @@
obj-$(CONFIG_GPIB_TMS9914) += tms9914.o
+901
View File
@@ -0,0 +1,901 @@
// SPDX-License-Identifier: GPL-2.0
/***************************************************************************
* copyright : (C) 2001, 2002 by Frank Mori Hess
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define dev_fmt pr_fmt
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/dma.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include "gpibP.h"
#include "tms9914.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB library for tms9914");
static unsigned int update_status_nolock(struct gpib_board *board, struct tms9914_priv *priv);
int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, int synchronous)
{
int i;
const int timeout = 100;
if (synchronous)
write_byte(priv, AUX_TCS, AUXCR);
else
write_byte(priv, AUX_TCA, AUXCR);
// busy wait until ATN is asserted
for (i = 0; i < timeout; i++) {
if ((read_byte(priv, ADSR) & HR_ATN))
break;
udelay(1);
}
if (i == timeout)
return -ETIMEDOUT;
clear_bit(WRITE_READY_BN, &priv->state);
return 0;
}
EXPORT_SYMBOL_GPL(tms9914_take_control);
/*
* The agilent 82350B has a buggy implementation of tcs which interferes with the
* operation of tca. It appears to be based on the controller state machine
* described in the TI 9900 TMS9914A data manual published in 1982. This
* manual describes tcs as putting the controller into a CWAS
* state where it waits indefinitely for ANRS and ignores tca. Since a
* functioning tca is far more important than tcs, we work around the
* problem by never issuing tcs.
*
* I don't know if this problem exists in the real tms9914a or just in the fpga
* of the 82350B. For now, only the agilent_82350b uses this workaround.
* The rest of the tms9914 based drivers still use tms9914_take_control
* directly (which does issue tcs).
*/
int tms9914_take_control_workaround(struct gpib_board *board,
struct tms9914_priv *priv, int synchronous)
{
if (synchronous)
return -ETIMEDOUT;
return tms9914_take_control(board, priv, synchronous);
}
EXPORT_SYMBOL_GPL(tms9914_take_control_workaround);
int tms9914_go_to_standby(struct gpib_board *board, struct tms9914_priv *priv)
{
int i;
const int timeout = 1000;
write_byte(priv, AUX_GTS, AUXCR);
// busy wait until ATN is released
for (i = 0; i < timeout; i++) {
if ((read_byte(priv, ADSR) & HR_ATN) == 0)
break;
udelay(1);
}
if (i == timeout)
return -ETIMEDOUT;
clear_bit(COMMAND_READY_BN, &priv->state);
return 0;
}
EXPORT_SYMBOL_GPL(tms9914_go_to_standby);
void tms9914_interface_clear(struct gpib_board *board, struct tms9914_priv *priv, int assert)
{
if (assert) {
write_byte(priv, AUX_SIC | AUX_CS, AUXCR);
set_bit(CIC_NUM, &board->status);
} else {
write_byte(priv, AUX_SIC, AUXCR);
}
}
EXPORT_SYMBOL_GPL(tms9914_interface_clear);
void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv, int enable)
{
if (enable)
write_byte(priv, AUX_SRE | AUX_CS, AUXCR);
else
write_byte(priv, AUX_SRE, AUXCR);
}
EXPORT_SYMBOL_GPL(tms9914_remote_enable);
int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
int request_control)
{
if (request_control) {
write_byte(priv, AUX_RQC, AUXCR);
} else {
clear_bit(CIC_NUM, &board->status);
write_byte(priv, AUX_RLC, AUXCR);
}
return 0;
}
EXPORT_SYMBOL_GPL(tms9914_request_system_control);
unsigned int tms9914_t1_delay(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int nano_sec)
{
static const int clock_period = 200; // assuming 5Mhz input clock
int num_cycles;
num_cycles = 12;
if (nano_sec <= 8 * clock_period) {
write_byte(priv, AUX_STDL | AUX_CS, AUXCR);
num_cycles = 8;
} else {
write_byte(priv, AUX_STDL, AUXCR);
}
if (nano_sec <= 4 * clock_period) {
write_byte(priv, AUX_VSTDL | AUX_CS, AUXCR);
num_cycles = 4;
} else {
write_byte(priv, AUX_VSTDL, AUXCR);
}
return num_cycles * clock_period;
}
EXPORT_SYMBOL_GPL(tms9914_t1_delay);
void tms9914_return_to_local(const struct gpib_board *board, struct tms9914_priv *priv)
{
write_byte(priv, AUX_RTL, AUXCR);
}
EXPORT_SYMBOL_GPL(tms9914_return_to_local);
void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode)
{
switch (mode) {
case TMS9914_HOLDOFF_NONE:
write_byte(priv, AUX_HLDE, AUXCR);
write_byte(priv, AUX_HLDA, AUXCR);
break;
case TMS9914_HOLDOFF_EOI:
write_byte(priv, AUX_HLDE | AUX_CS, AUXCR);
write_byte(priv, AUX_HLDA, AUXCR);
break;
case TMS9914_HOLDOFF_ALL:
write_byte(priv, AUX_HLDE, AUXCR);
write_byte(priv, AUX_HLDA | AUX_CS, AUXCR);
break;
default:
pr_err("bug! bad holdoff mode %i\n", mode);
break;
}
priv->holdoff_mode = mode;
}
EXPORT_SYMBOL_GPL(tms9914_set_holdoff_mode);
void tms9914_release_holdoff(struct tms9914_priv *priv)
{
if (priv->holdoff_active) {
write_byte(priv, AUX_RHDF, AUXCR);
priv->holdoff_active = 0;
}
}
EXPORT_SYMBOL_GPL(tms9914_release_holdoff);
int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_byte,
int compare_8_bits)
{
priv->eos = eos_byte;
priv->eos_flags = REOS;
if (compare_8_bits)
priv->eos_flags |= BIN;
return 0;
}
EXPORT_SYMBOL(tms9914_enable_eos);
void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv)
{
priv->eos_flags &= ~REOS;
}
EXPORT_SYMBOL(tms9914_disable_eos);
int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result)
{
// execute parallel poll
write_byte(priv, AUX_CS | AUX_RPP, AUXCR);
udelay(2);
*result = read_byte(priv, CPTR);
// clear parallel poll state
write_byte(priv, AUX_RPP, AUXCR);
return 0;
}
EXPORT_SYMBOL(tms9914_parallel_poll);
static void set_ppoll_reg(struct tms9914_priv *priv, int enable,
unsigned int dio_line, int sense, int ist)
{
u8 dio_byte;
if (enable && ((sense && ist) || (!sense && !ist))) {
dio_byte = 1 << (dio_line - 1);
write_byte(priv, dio_byte, PPR);
} else {
write_byte(priv, 0, PPR);
}
}
void tms9914_parallel_poll_configure(struct gpib_board *board,
struct tms9914_priv *priv, u8 config)
{
priv->ppoll_enable = (config & PPC_DISABLE) == 0;
priv->ppoll_line = (config & PPC_DIO_MASK) + 1;
priv->ppoll_sense = (config & PPC_SENSE) != 0;
set_ppoll_reg(priv, priv->ppoll_enable, priv->ppoll_line, priv->ppoll_sense, board->ist);
}
EXPORT_SYMBOL(tms9914_parallel_poll_configure);
void tms9914_parallel_poll_response(struct gpib_board *board,
struct tms9914_priv *priv, int ist)
{
set_ppoll_reg(priv, priv->ppoll_enable, priv->ppoll_line, priv->ppoll_sense, ist);
}
EXPORT_SYMBOL(tms9914_parallel_poll_response);
void tms9914_serial_poll_response(struct gpib_board *board,
struct tms9914_priv *priv, u8 status)
{
unsigned long flags;
spin_lock_irqsave(&board->spinlock, flags);
write_byte(priv, status, SPMR);
priv->spoll_status = status;
if (status & request_service_bit)
write_byte(priv, AUX_RSV2 | AUX_CS, AUXCR);
else
write_byte(priv, AUX_RSV2, AUXCR);
spin_unlock_irqrestore(&board->spinlock, flags);
}
EXPORT_SYMBOL(tms9914_serial_poll_response);
u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv)
{
u8 status;
unsigned long flags;
spin_lock_irqsave(&board->spinlock, flags);
status = priv->spoll_status;
spin_unlock_irqrestore(&board->spinlock, flags);
return status;
}
EXPORT_SYMBOL(tms9914_serial_poll_status);
int tms9914_primary_address(struct gpib_board *board,
struct tms9914_priv *priv, unsigned int address)
{
// put primary address in address0
write_byte(priv, address & ADDRESS_MASK, ADR);
return 0;
}
EXPORT_SYMBOL(tms9914_primary_address);
int tms9914_secondary_address(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int address, int enable)
{
if (enable)
priv->imr1_bits |= HR_APTIE;
else
priv->imr1_bits &= ~HR_APTIE;
write_byte(priv, priv->imr1_bits, IMR1);
return 0;
}
EXPORT_SYMBOL(tms9914_secondary_address);
unsigned int tms9914_update_status(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int clear_mask)
{
unsigned long flags;
unsigned int retval;
spin_lock_irqsave(&board->spinlock, flags);
retval = update_status_nolock(board, priv);
board->status &= ~clear_mask;
spin_unlock_irqrestore(&board->spinlock, flags);
return retval;
}
EXPORT_SYMBOL(tms9914_update_status);
static void update_talker_state(struct tms9914_priv *priv, unsigned int address_status_bits)
{
if (address_status_bits & HR_TA) {
if (address_status_bits & HR_ATN)
priv->talker_state = talker_addressed;
else
/*
* this could also be serial_poll_active, but the tms9914 provides no
* way to distinguish, so we'll assume talker_active
*/
priv->talker_state = talker_active;
} else {
priv->talker_state = talker_idle;
}
}
static void update_listener_state(struct tms9914_priv *priv, unsigned int address_status_bits)
{
if (address_status_bits & HR_LA) {
if (address_status_bits & HR_ATN)
priv->listener_state = listener_addressed;
else
priv->listener_state = listener_active;
} else {
priv->listener_state = listener_idle;
}
}
static unsigned int update_status_nolock(struct gpib_board *board, struct tms9914_priv *priv)
{
int address_status;
int bsr_bits;
address_status = read_byte(priv, ADSR);
// check for remote/local
if (address_status & HR_REM)
set_bit(REM_NUM, &board->status);
else
clear_bit(REM_NUM, &board->status);
// check for lockout
if (address_status & HR_LLO)
set_bit(LOK_NUM, &board->status);
else
clear_bit(LOK_NUM, &board->status);
// check for ATN
if (address_status & HR_ATN)
set_bit(ATN_NUM, &board->status);
else
clear_bit(ATN_NUM, &board->status);
// check for talker/listener addressed
update_talker_state(priv, address_status);
if (priv->talker_state == talker_active || priv->talker_state == talker_addressed)
set_bit(TACS_NUM, &board->status);
else
clear_bit(TACS_NUM, &board->status);
update_listener_state(priv, address_status);
if (priv->listener_state == listener_active || priv->listener_state == listener_addressed)
set_bit(LACS_NUM, &board->status);
else
clear_bit(LACS_NUM, &board->status);
// Check for SRQI - not reset elsewhere except in autospoll
if (board->status & SRQI) {
bsr_bits = read_byte(priv, BSR);
if (!(bsr_bits & BSR_SRQ_BIT))
clear_bit(SRQI_NUM, &board->status);
}
dev_dbg(board->gpib_dev, "status 0x%lx, state 0x%lx\n", board->status, priv->state);
return board->status;
}
int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *priv)
{
int bsr_bits;
int status = VALID_ALL;
bsr_bits = read_byte(priv, BSR);
if (bsr_bits & BSR_REN_BIT)
status |= BUS_REN;
if (bsr_bits & BSR_IFC_BIT)
status |= BUS_IFC;
if (bsr_bits & BSR_SRQ_BIT)
status |= BUS_SRQ;
if (bsr_bits & BSR_EOI_BIT)
status |= BUS_EOI;
if (bsr_bits & BSR_NRFD_BIT)
status |= BUS_NRFD;
if (bsr_bits & BSR_NDAC_BIT)
status |= BUS_NDAC;
if (bsr_bits & BSR_DAV_BIT)
status |= BUS_DAV;
if (bsr_bits & BSR_ATN_BIT)
status |= BUS_ATN;
return status;
}
EXPORT_SYMBOL(tms9914_line_status);
static int check_for_eos(struct tms9914_priv *priv, u8 byte)
{
static const u8 seven_bit_compare_mask = 0x7f;
if ((priv->eos_flags & REOS) == 0)
return 0;
if (priv->eos_flags & BIN) {
if (priv->eos == byte)
return 1;
} else {
if ((priv->eos & seven_bit_compare_mask) == (byte & seven_bit_compare_mask))
return 1;
}
return 0;
}
static int wait_for_read_byte(struct gpib_board *board, struct tms9914_priv *priv)
{
if (wait_event_interruptible(board->wait,
test_bit(READ_READY_BN, &priv->state) ||
test_bit(DEV_CLEAR_BN, &priv->state) ||
test_bit(TIMO_NUM, &board->status)))
return -ERESTARTSYS;
if (test_bit(TIMO_NUM, &board->status))
return -ETIMEDOUT;
if (test_bit(DEV_CLEAR_BN, &priv->state))
return -EINTR;
return 0;
}
static inline u8 tms9914_read_data_in(struct gpib_board *board,
struct tms9914_priv *priv, int *end)
{
unsigned long flags;
u8 data;
spin_lock_irqsave(&board->spinlock, flags);
clear_bit(READ_READY_BN, &priv->state);
data = read_byte(priv, DIR);
if (test_and_clear_bit(RECEIVED_END_BN, &priv->state))
*end = 1;
else
*end = 0;
switch (priv->holdoff_mode) {
case TMS9914_HOLDOFF_EOI:
if (*end)
priv->holdoff_active = 1;
break;
case TMS9914_HOLDOFF_ALL:
priv->holdoff_active = 1;
break;
case TMS9914_HOLDOFF_NONE:
break;
default:
dev_err(board->gpib_dev, "bug! bad holdoff mode %i\n", priv->holdoff_mode);
break;
}
spin_unlock_irqrestore(&board->spinlock, flags);
return data;
}
static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
*bytes_read = 0;
*end = 0;
while (*bytes_read < length && *end == 0) {
tms9914_release_holdoff(priv);
retval = wait_for_read_byte(board, priv);
if (retval < 0)
return retval;
buffer[(*bytes_read)++] = tms9914_read_data_in(board, priv, end);
if (check_for_eos(priv, buffer[*bytes_read - 1]))
*end = 1;
}
return retval;
}
int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
size_t num_bytes;
*end = 0;
*bytes_read = 0;
if (length == 0)
return 0;
clear_bit(DEV_CLEAR_BN, &priv->state);
// transfer data (except for last byte)
if (length > 1) {
if (priv->eos_flags & REOS)
tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL);
else
tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_EOI);
// PIO transfer
retval = pio_read(board, priv, buffer, length - 1, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
return retval;
buffer += num_bytes;
length -= num_bytes;
}
// read last bytes if we haven't received an END yet
if (*end == 0) {
// make sure we holdoff after last byte read
tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL);
retval = pio_read(board, priv, buffer, length, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
return retval;
}
return 0;
}
EXPORT_SYMBOL(tms9914_read);
static int pio_write_wait(struct gpib_board *board, struct tms9914_priv *priv)
{
// wait until next byte is ready to be sent
if (wait_event_interruptible(board->wait,
test_bit(WRITE_READY_BN, &priv->state) ||
test_bit(BUS_ERROR_BN, &priv->state) ||
test_bit(DEV_CLEAR_BN, &priv->state) ||
test_bit(TIMO_NUM, &board->status)))
return -ERESTARTSYS;
if (test_bit(TIMO_NUM, &board->status))
return -ETIMEDOUT;
if (test_bit(BUS_ERROR_BN, &priv->state))
return -EIO;
if (test_bit(DEV_CLEAR_BN, &priv->state))
return -EINTR;
return 0;
}
static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written)
{
ssize_t retval = 0;
unsigned long flags;
*bytes_written = 0;
while (*bytes_written < length) {
retval = pio_write_wait(board, priv);
if (retval < 0)
break;
spin_lock_irqsave(&board->spinlock, flags);
clear_bit(WRITE_READY_BN, &priv->state);
write_byte(priv, buffer[(*bytes_written)++], CDOR);
spin_unlock_irqrestore(&board->spinlock, flags);
}
retval = pio_write_wait(board, priv);
if (retval < 0)
return retval;
return length;
}
int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv,
u8 *buffer, size_t length, int send_eoi, size_t *bytes_written)
{
ssize_t retval = 0;
*bytes_written = 0;
if (length == 0)
return 0;
clear_bit(BUS_ERROR_BN, &priv->state);
clear_bit(DEV_CLEAR_BN, &priv->state);
if (send_eoi)
length-- ; /* save the last byte for sending EOI */
if (length > 0) {
size_t num_bytes;
// PIO transfer
retval = pio_write(board, priv, buffer, length, &num_bytes);
*bytes_written += num_bytes;
if (retval < 0)
return retval;
}
if (send_eoi) {
size_t num_bytes;
/*send EOI */
write_byte(priv, AUX_SEOI, AUXCR);
retval = pio_write(board, priv, &buffer[*bytes_written], 1, &num_bytes);
*bytes_written += num_bytes;
}
return retval;
}
EXPORT_SYMBOL(tms9914_write);
static void check_my_address_state(struct gpib_board *board,
struct tms9914_priv *priv, int cmd_byte)
{
if (cmd_byte == MLA(board->pad)) {
priv->primary_listen_addressed = 1;
// become active listener
if (board->sad < 0)
write_byte(priv, AUX_LON | AUX_CS, AUXCR);
} else if (board->sad >= 0 && priv->primary_listen_addressed &&
cmd_byte == MSA(board->sad)) {
// become active listener
write_byte(priv, AUX_LON | AUX_CS, AUXCR);
} else if (cmd_byte != MLA(board->pad) && (cmd_byte & 0xe0) == LAD) {
priv->primary_listen_addressed = 0;
} else if (cmd_byte == UNL) {
priv->primary_listen_addressed = 0;
write_byte(priv, AUX_LON, AUXCR);
} else if (cmd_byte == MTA(board->pad)) {
priv->primary_talk_addressed = 1;
if (board->sad < 0)
// make active talker
write_byte(priv, AUX_TON | AUX_CS, AUXCR);
} else if (board->sad >= 0 && priv->primary_talk_addressed &&
cmd_byte == MSA(board->sad)) {
// become active talker
write_byte(priv, AUX_TON | AUX_CS, AUXCR);
} else if (cmd_byte != MTA(board->pad) && (cmd_byte & 0xe0) == TAD) {
// Other Talk Address
priv->primary_talk_addressed = 0;
write_byte(priv, AUX_TON, AUXCR);
} else if (cmd_byte == UNT) {
priv->primary_talk_addressed = 0;
write_byte(priv, AUX_TON, AUXCR);
}
}
int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written)
{
int retval = 0;
unsigned long flags;
*bytes_written = 0;
while (*bytes_written < length) {
if (wait_event_interruptible(board->wait,
test_bit(COMMAND_READY_BN,
&priv->state) ||
test_bit(TIMO_NUM, &board->status)))
break;
if (test_bit(TIMO_NUM, &board->status))
break;
spin_lock_irqsave(&board->spinlock, flags);
clear_bit(COMMAND_READY_BN, &priv->state);
write_byte(priv, buffer[*bytes_written], CDOR);
spin_unlock_irqrestore(&board->spinlock, flags);
check_my_address_state(board, priv, buffer[*bytes_written]);
++(*bytes_written);
}
// wait until last command byte is written
if (wait_event_interruptible(board->wait,
test_bit(COMMAND_READY_BN,
&priv->state) || test_bit(TIMO_NUM, &board->status)))
retval = -ERESTARTSYS;
if (test_bit(TIMO_NUM, &board->status))
retval = -ETIMEDOUT;
return retval;
}
EXPORT_SYMBOL(tms9914_command);
irqreturn_t tms9914_interrupt(struct gpib_board *board, struct tms9914_priv *priv)
{
int status0, status1;
// read interrupt status (also clears status)
status0 = read_byte(priv, ISR0);
status1 = read_byte(priv, ISR1);
return tms9914_interrupt_have_status(board, priv, status0, status1);
}
EXPORT_SYMBOL(tms9914_interrupt);
irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms9914_priv *priv,
int status0, int status1)
{
// record reception of END
if (status0 & HR_END)
set_bit(RECEIVED_END_BN, &priv->state);
// get incoming data in PIO mode
if ((status0 & HR_BI))
set_bit(READ_READY_BN, &priv->state);
if ((status0 & HR_BO)) {
if (read_byte(priv, ADSR) & HR_ATN)
set_bit(COMMAND_READY_BN, &priv->state);
else
set_bit(WRITE_READY_BN, &priv->state);
}
if (status0 & HR_SPAS) {
priv->spoll_status &= ~request_service_bit;
write_byte(priv, priv->spoll_status, SPMR);
// FIXME: set SPOLL status bit
}
// record service request in status
if (status1 & HR_SRQ)
set_bit(SRQI_NUM, &board->status);
// have been addressed (with secondary addressing disabled)
if (status1 & HR_MA)
// clear dac holdoff
write_byte(priv, AUX_VAL, AUXCR);
// unrecognized command received
if (status1 & HR_UNC) {
unsigned short command_byte = read_byte(priv, CPTR) & gpib_command_mask;
switch (command_byte) {
case PP_CONFIG:
priv->ppoll_configure_state = 1;
/*
* AUX_PTS generates another UNC interrupt on the next command byte
* if it is in the secondary address group (such as PPE and PPD).
*/
write_byte(priv, AUX_PTS, AUXCR);
write_byte(priv, AUX_VAL, AUXCR);
break;
case PPU:
tms9914_parallel_poll_configure(board, priv, command_byte);
write_byte(priv, AUX_VAL, AUXCR);
break;
default:
if (is_PPE(command_byte) || is_PPD(command_byte)) {
if (priv->ppoll_configure_state) {
tms9914_parallel_poll_configure(board, priv, command_byte);
write_byte(priv, AUX_VAL, AUXCR);
} else {// bad parallel poll configure byte
// clear dac holdoff
write_byte(priv, AUX_INVAL, AUXCR);
}
} else {
// clear dac holdoff
write_byte(priv, AUX_INVAL, AUXCR);
}
break;
}
if (in_primary_command_group(command_byte) && command_byte != PP_CONFIG)
priv->ppoll_configure_state = 0;
}
if (status1 & HR_ERR) {
dev_dbg(board->gpib_dev, "gpib bus error\n");
set_bit(BUS_ERROR_BN, &priv->state);
}
if (status1 & HR_IFC) {
push_gpib_event(board, EVENT_IFC);
clear_bit(CIC_NUM, &board->status);
}
if (status1 & HR_GET) {
push_gpib_event(board, EVENT_DEV_TRG);
// clear dac holdoff
write_byte(priv, AUX_VAL, AUXCR);
}
if (status1 & HR_DCAS) {
push_gpib_event(board, EVENT_DEV_CLR);
// clear dac holdoff
write_byte(priv, AUX_VAL, AUXCR);
set_bit(DEV_CLEAR_BN, &priv->state);
}
// check for being addressed with secondary addressing
if (status1 & HR_APT) {
if (board->sad < 0)
dev_err(board->gpib_dev, "bug, APT interrupt without secondary addressing?\n");
if ((read_byte(priv, CPTR) & gpib_command_mask) == MSA(board->sad))
write_byte(priv, AUX_VAL, AUXCR);
else
write_byte(priv, AUX_INVAL, AUXCR);
}
if ((status0 & priv->imr0_bits) || (status1 & priv->imr1_bits)) {
dev_dbg(board->gpib_dev, "isr0 0x%x, imr0 0x%x, isr1 0x%x, imr1 0x%x\n",
status0, priv->imr0_bits, status1, priv->imr1_bits);
update_status_nolock(board, priv);
wake_up_interruptible(&board->wait);
}
return IRQ_HANDLED;
}
EXPORT_SYMBOL(tms9914_interrupt_have_status);
void tms9914_board_reset(struct tms9914_priv *priv)
{
/* chip reset */
write_byte(priv, AUX_CHIP_RESET | AUX_CS, AUXCR);
/* disable all interrupts */
priv->imr0_bits = 0;
write_byte(priv, priv->imr0_bits, IMR0);
priv->imr1_bits = 0;
write_byte(priv, priv->imr1_bits, IMR1);
write_byte(priv, AUX_DAI | AUX_CS, AUXCR);
/* clear registers by reading */
read_byte(priv, CPTR);
read_byte(priv, ISR0);
read_byte(priv, ISR1);
write_byte(priv, 0, SPMR);
/* parallel poll unconfigure */
write_byte(priv, 0, PPR);
/* request for data holdoff */
tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL);
}
EXPORT_SYMBOL_GPL(tms9914_board_reset);
void tms9914_online(struct gpib_board *board, struct tms9914_priv *priv)
{
/* set GPIB address */
tms9914_primary_address(board, priv, board->pad);
tms9914_secondary_address(board, priv, board->sad, board->sad >= 0);
/* enable tms9914 interrupts */
priv->imr0_bits |= HR_MACIE | HR_RLCIE | HR_ENDIE | HR_BOIE | HR_BIIE |
HR_SPASIE;
priv->imr1_bits |= HR_MAIE | HR_SRQIE | HR_UNCIE | HR_ERRIE | HR_IFCIE |
HR_GETIE | HR_DCASIE;
write_byte(priv, priv->imr0_bits, IMR0);
write_byte(priv, priv->imr1_bits, IMR1);
write_byte(priv, AUX_DAI, AUXCR);
/* turn off reset state */
write_byte(priv, AUX_CHIP_RESET, AUXCR);
}
EXPORT_SYMBOL_GPL(tms9914_online);
#ifdef CONFIG_HAS_IOPORT
// wrapper for inb
u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return inb(priv->iobase + register_num * priv->offset);
}
EXPORT_SYMBOL_GPL(tms9914_ioport_read_byte);
// wrapper for outb
void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
outb(data, priv->iobase + register_num * priv->offset);
if (register_num == AUXCR)
udelay(1);
}
EXPORT_SYMBOL_GPL(tms9914_ioport_write_byte);
#endif
// wrapper for readb
u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return readb(priv->mmiobase + register_num * priv->offset);
}
EXPORT_SYMBOL_GPL(tms9914_iomem_read_byte);
// wrapper for writeb
void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
writeb(data, priv->mmiobase + register_num * priv->offset);
if (register_num == AUXCR)
udelay(1);
}
EXPORT_SYMBOL_GPL(tms9914_iomem_write_byte);
@@ -0,0 +1,6 @@
obj-$(CONFIG_GPIB_NI_PCI_ISA) += tnt4882.o
tnt4882-objs := tnt4882_gpib.o mite.o
+133
View File
@@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Hardware driver for NI Mite PCI interface chip,
* adapted from COMEDI
*
* Copyright (C) 1997-8 David A. Schleef
* Copyright (C) 2002 Frank Mori Hess
*
* The PCI-MIO E series driver was originally written by
* Tomasz Motylewski <...>, and ported to comedi by ds.
*
* References for specifications:
*
* 321747b.pdf Register Level Programmer Manual (obsolete)
* 321747c.pdf Register Level Programmer Manual (new)
* DAQ-STC reference manual
*
* Other possibly relevant info:
*
* 320517c.pdf User manual (obsolete)
* 320517f.pdf User manual (new)
* 320889a.pdf delete
* 320906c.pdf maximum signal ratings
* 321066a.pdf about 16x
* 321791a.pdf discontinuation of at-mio-16e-10 rev. c
* 321808a.pdf about at-mio-16e-10 rev P
* 321837a.pdf discontinuation of at-mio-16de-10 rev d
* 321838a.pdf about at-mio-16de-10 rev N
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "mite.h"
#define PCI_MITE_SIZE 4096
#define PCI_DAQ_SIZE 4096
struct mite_struct *mite_devices;
#define TOP_OF_PAGE(x) ((x) | (~(PAGE_MASK)))
void mite_init(void)
{
struct pci_dev *pcidev;
struct mite_struct *mite;
for (pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, NULL);
pcidev;
pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, pcidev)) {
mite = kzalloc_obj(*mite);
if (!mite)
return;
mite->pcidev = pcidev;
pci_dev_get(mite->pcidev);
mite->next = mite_devices;
mite_devices = mite;
}
}
int mite_setup(struct mite_struct *mite)
{
u32 addr;
if (pci_enable_device(mite->pcidev)) {
pr_err("mite: error enabling mite.\n");
return -EIO;
}
pci_set_master(mite->pcidev);
if (pci_request_regions(mite->pcidev, "mite")) {
pr_err("mite: failed to request mite io regions.\n");
return -EIO;
}
addr = pci_resource_start(mite->pcidev, 0);
mite->mite_phys_addr = addr;
mite->mite_io_addr = ioremap(addr, pci_resource_len(mite->pcidev, 0));
if (!mite->mite_io_addr) {
pr_err("mite: failed to remap mite io memory address.\n");
return -ENOMEM;
}
addr = pci_resource_start(mite->pcidev, 1);
mite->daq_phys_addr = addr;
mite->daq_io_addr = ioremap(mite->daq_phys_addr, pci_resource_len(mite->pcidev, 1));
if (!mite->daq_io_addr) {
pr_err("mite: failed to remap daq io memory address.\n");
return -ENOMEM;
}
writel(mite->daq_phys_addr | WENAB, mite->mite_io_addr + MITE_IODWBSR);
mite->used = 1;
return 0;
}
void mite_cleanup(void)
{
struct mite_struct *mite, *next;
for (mite = mite_devices; mite; mite = next) {
next = mite->next;
if (mite->pcidev)
pci_dev_put(mite->pcidev);
kfree(mite);
}
}
void mite_unsetup(struct mite_struct *mite)
{
if (!mite)
return;
if (mite->mite_io_addr) {
iounmap(mite->mite_io_addr);
mite->mite_io_addr = NULL;
}
if (mite->daq_io_addr) {
iounmap(mite->daq_io_addr);
mite->daq_io_addr = NULL;
}
if (mite->mite_phys_addr) {
pci_release_regions(mite->pcidev);
pci_disable_device(mite->pcidev);
mite->mite_phys_addr = 0;
}
mite->used = 0;
}
+234
View File
@@ -0,0 +1,234 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Hardware driver for NI Mite PCI interface chip
*
* Copyright (C) 1999 David A. Schleef <ds@stm.lbl.gov>
*/
#ifndef _MITE_H_
#define _MITE_H_
#include <linux/pci.h>
#define PCI_VENDOR_ID_NATINST 0x1093
//#define DEBUG_MITE
#ifdef DEBUG_MITE
#define MDPRINTK(format, args...) pr_debug(format, ## args)
#else
#define MDPRINTK(args...)
#endif
#define MITE_RING_SIZE 3000
struct mite_dma_chain {
u32 count;
u32 addr;
u32 next;
};
struct mite_struct {
struct mite_struct *next;
int used;
struct pci_dev *pcidev;
unsigned long mite_phys_addr;
void __iomem *mite_io_addr;
unsigned long daq_phys_addr;
void __iomem *daq_io_addr;
int DMA_CheckNearEnd;
struct mite_dma_chain ring[MITE_RING_SIZE];
};
extern struct mite_struct *mite_devices;
extern inline unsigned int mite_irq(struct mite_struct *mite)
{
return mite->pcidev->irq;
};
extern inline unsigned int mite_device_id(struct mite_struct *mite)
{
return mite->pcidev->device;
};
void mite_init(void);
void mite_cleanup(void);
int mite_setup(struct mite_struct *mite);
void mite_unsetup(struct mite_struct *mite);
void mite_list_devices(void);
#define CHAN_OFFSET(x) (0x100 * (x))
/* DMA base for chan 0 is 0x500, chan 1 is 0x600 */
#define MITE_CHOR 0x500
#define CHOR_DMARESET BIT(31)
#define CHOR_SET_SEND_TC BIT(11)
#define CHOR_CLR_SEND_TC BIT(10)
#define CHOR_SET_LPAUSE BIT(9)
#define CHOR_CLR_LPAUSE BIT(8)
#define CHOR_CLRDONE BIT(7)
#define CHOR_CLRRB BIT(6)
#define CHOR_CLRLC BIT(5)
#define CHOR_FRESET BIT(4)
#define CHOR_ABORT BIT(3)
#define CHOR_STOP BIT(2)
#define CHOR_CONT BIT(1)
#define CHOR_START BIT(0)
#define CHOR_PON (CHOR_CLR_SEND_TC | CHOR_CLR_LPAUSE)
#define MITE_CHCR 0x504
#define CHCR_SET_DMA_IE BIT(31)
#define CHCR_CLR_DMA_IE BIT(30)
#define CHCR_SET_LINKP_IE BIT(29)
#define CHCR_CLR_LINKP_IE BIT(28)
#define CHCR_SET_SAR_IE BIT(27)
#define CHCR_CLR_SAR_IE BIT(26)
#define CHCR_SET_DONE_IE BIT(25)
#define CHCR_CLR_DONE_IE BIT(24)
#define CHCR_SET_MRDY_IE BIT(23)
#define CHCR_CLR_MRDY_IE BIT(22)
#define CHCR_SET_DRDY_IE BIT(21)
#define CHCR_CLR_DRDY_IE BIT(20)
#define CHCR_SET_LC_IE BIT(19)
#define CHCR_CLR_LC_IE BIT(18)
#define CHCR_SET_CONT_RB_IE BIT(17)
#define CHCR_CLR_CONT_RB_IE BIT(16)
#define CHCR_FIFODIS BIT(15)
#define CHCR_FIFO_ON 0
#define CHCR_BURSTEN BIT(14)
#define CHCR_NO_BURSTEN 0
#define CHCR_NFTP(x) ((x) << 11)
#define CHCR_NFTP0 CHCR_NFTP(0)
#define CHCR_NFTP1 CHCR_NFTP(1)
#define CHCR_NFTP2 CHCR_NFTP(2)
#define CHCR_NFTP4 CHCR_NFTP(3)
#define CHCR_NFTP8 CHCR_NFTP(4)
#define CHCR_NFTP16 CHCR_NFTP(5)
#define CHCR_NETP(x) ((x) << 11)
#define CHCR_NETP0 CHCR_NETP(0)
#define CHCR_NETP1 CHCR_NETP(1)
#define CHCR_NETP2 CHCR_NETP(2)
#define CHCR_NETP4 CHCR_NETP(3)
#define CHCR_NETP8 CHCR_NETP(4)
#define CHCR_CHEND1 BIT(5)
#define CHCR_CHEND0 BIT(4)
#define CHCR_DIR BIT(3)
#define CHCR_DEV_TO_MEM CHCR_DIR
#define CHCR_MEM_TO_DEV 0
#define CHCR_NORMAL ((0) << 0)
#define CHCR_CONTINUE ((1) << 0)
#define CHCR_RINGBUFF ((2) << 0)
#define CHCR_LINKSHORT ((4) << 0)
#define CHCR_LINKLONG ((5) << 0)
#define CHCRPON (CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE | CHCR_CLR_SAR_IE | \
CHCR_CLR_DONE_IE | CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE | \
CHCR_CLR_LC_IE | CHCR_CLR_CONT_IE)
#define MITE_TCR 0x508
/* CR bits */
#define CR_RL(x) ((x) << 21)
#define CR_RL0 CR_RL(0)
#define CR_RL1 CR_RL(1)
#define CR_RL2 CR_RL(2)
#define CR_RL4 CR_RL(3)
#define CR_RL8 CR_RL(4)
#define CR_RL16 CR_RL(5)
#define CR_RL32 CR_RL(6)
#define CR_RL64 CR_RL(7)
#define CR_RD(x) ((x) << 19)
#define CR_RD0 CR_RD(0)
#define CR_RD32 CR_RD(1)
#define CR_RD512 CR_RD(2)
#define CR_RD8192 CR_RD(3)
#define CR_REQS(x) ((x) << 16)
#define CR_REQSDRQ0 CR_REQS(4)
#define CR_REQSDRQ1 CR_REQS(5)
#define CR_REQSDRQ2 CR_REQS(6)
#define CR_REQSDRQ3 CR_REQS(7)
#define CR_ASEQX(x) ((x) << 10)
#define CR_ASEQX0 CR_ASEQX(0)
#define CR_ASEQDONT CR_ASEQX0
#define CR_ASEQXP1 CR_ASEQX(1)
#define CR_ASEQUP CR_ASEQXP1
#define CR_ASEQXP2 CR_ASEQX(2)
#define CR_ASEQDOWN CR_ASEQXP2
#define CR_ASEQXP4 CR_ASEQX(3)
#define CR_ASEQXP8 CR_ASEQX(4)
#define CR_ASEQXP16 CR_ASEQX(5)
#define CR_ASEQXP32 CR_ASEQX(6)
#define CR_ASEQXP64 CR_ASEQX(7)
#define CR_ASEQXM1 CR_ASEQX(9)
#define CR_ASEQXM2 CR_ASEQX(10)
#define CR_ASEQXM4 CR_ASEQX(11)
#define CR_ASEQXM8 CR_ASEQX(12)
#define CR_ASEQXM16 CR_ASEQX(13)
#define CR_ASEQXM32 CR_ASEQX(14)
#define CR_ASEQXM64 CR_ASEQX(15)
#define CR_PSIZEBYTE BIT(8)
#define CR_PSIZEHALF (2 << 8)
#define CR_PSIZEWORD (3 << 8)
#define CR_PORTCPU (0 << 6)
#define CR_PORTIO BIT(6)
#define CR_PORTVXI (2 << 6)
#define CR_PORTMXI (3 << 6)
#define CR_AMDEVICE BIT(0)
#define CHSR_INT 0x80000000
#define CHSR_DONE 0x02000000
#define CHSR_LINKC 0x00080000
#define MITE_MCR 0x50c
#define MCRPON 0
#define MITE_MAR 0x510
#define MITE_DCR 0x514
#define DCR_NORMAL BIT(29)
#define DCRPON 0
#define MITE_DAR 0x518
#define MITE_LKCR 0x51c
#define MITE_LKAR 0x520
#define MITE_LLKAR 0x524
#define MITE_BAR 0x528
#define MITE_BCR 0x52c
#define MITE_SAR 0x530
#define MITE_WSCR 0x534
#define MITE_WSER 0x538
#define MITE_CHSR 0x53c
#define MITE_FCR 0x540
#define MITE_FIFO 0x80
#define MITE_FIFOEND 0xff
#define MITE_AMRAM 0x00
#define MITE_AMDEVICE 0x01
#define MITE_AMHOST_A32_SINGLE 0x09
#define MITE_AMHOST_A24_SINGLE 0x39
#define MITE_AMHOST_A16_SINGLE 0x29
#define MITE_AMHOST_A32_BLOCK 0x0b
#define MITE_AMHOST_A32D64_BLOCK 0x08
#define MITE_AMHOST_A24_BLOCK 0x3b
enum mite_registers {
MITE_IODWBSR = 0xc0, // IO Device Window Base Size Register
MITE_CSIGR = 0x460, // chip signature
MITE_IODWBSR_1 = 0xc4, // IO Device Window Base Size Register 1 (used by 6602 boards)
MITE_IODWCR_1 = 0xf4
};
enum MITE_IODWBSR_bits {
WENAB = 0x80, // window enable
WENAB_6602 = 0x8c // window enable for 6602 boards
};
#endif
File diff suppressed because it is too large Load Diff