Files
linux/drivers/gpib/tms9914/tms9914.c
Dave Penkler e6ab504633 staging: gpib: Destage gpib
Move the gpib drivers out of staging and into the "real" part of the
kernel.  This entails:

 - Remove the gpib Kconfig menu and Makefile build rule from staging.
 - Remove gpib/uapi from the header file search path in subdir-ccflags
   of the gpib Makefile
 - move the gpib/uapi files to include/uapi/linux
 - Move the gpib tree out of staging to drivers.
 - Remove the word "Linux" from the gpib Kconfig file.
 - Add the gpib Kconfig menu and Makefile build rule to drivers

Signed-off-by: Dave Penkler <dpenkler@gmail.com>
Link: https://patch.msgid.link/20251117144021.23569-5-dpenkler@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-11-24 17:52:11 +01:00

915 lines
24 KiB
C

// 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);
static int __init tms9914_init_module(void)
{
return 0;
}
static void __exit tms9914_exit_module(void)
{
}
module_init(tms9914_init_module);
module_exit(tms9914_exit_module);