mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git
synced 2026-04-05 00:08:32 -04:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1502 lines
43 KiB
C
1502 lines
43 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/***************************************************************************
|
|
* copyright : (C) 1999 Axel Dziemba (axel.dziemba@ines.de)
|
|
* (C) 2002 by Frank Mori Hess
|
|
***************************************************************************/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#define dev_fmt pr_fmt
|
|
#define DRV_NAME KBUILD_MODNAME
|
|
|
|
#include "ines.h"
|
|
|
|
#include <linux/pci.h>
|
|
#include <linux/pci_ids.h>
|
|
#include <linux/bitops.h>
|
|
#include <asm/dma.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include "gpib_pci_ids.h"
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("GPIB driver for Ines iGPIB 72010");
|
|
|
|
static irqreturn_t ines_interrupt(struct gpib_board *board);
|
|
|
|
static int ines_line_status(const struct gpib_board *board)
|
|
{
|
|
int status = VALID_ALL;
|
|
int bcm_bits;
|
|
struct ines_priv *ines_priv;
|
|
|
|
ines_priv = board->private_data;
|
|
|
|
bcm_bits = ines_inb(ines_priv, BUS_CONTROL_MONITOR);
|
|
|
|
if (bcm_bits & BCM_REN_BIT)
|
|
status |= BUS_REN;
|
|
if (bcm_bits & BCM_IFC_BIT)
|
|
status |= BUS_IFC;
|
|
if (bcm_bits & BCM_SRQ_BIT)
|
|
status |= BUS_SRQ;
|
|
if (bcm_bits & BCM_EOI_BIT)
|
|
status |= BUS_EOI;
|
|
if (bcm_bits & BCM_NRFD_BIT)
|
|
status |= BUS_NRFD;
|
|
if (bcm_bits & BCM_NDAC_BIT)
|
|
status |= BUS_NDAC;
|
|
if (bcm_bits & BCM_DAV_BIT)
|
|
status |= BUS_DAV;
|
|
if (bcm_bits & BCM_ATN_BIT)
|
|
status |= BUS_ATN;
|
|
|
|
return status;
|
|
}
|
|
|
|
static void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count)
|
|
{
|
|
if (count > 0xffff) {
|
|
pr_err("bug! tried to set xfer counter > 0xffff\n");
|
|
return;
|
|
}
|
|
ines_outb(priv, (count >> 8) & 0xff, XFER_COUNT_UPPER);
|
|
ines_outb(priv, count & 0xff, XFER_COUNT_LOWER);
|
|
}
|
|
|
|
static int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec)
|
|
{
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
unsigned int retval;
|
|
|
|
retval = nec7210_t1_delay(board, nec_priv, nano_sec);
|
|
|
|
if (nano_sec <= 250) {
|
|
write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_250ns |
|
|
INES_INITIAL_T1_2000ns, AUXMR);
|
|
retval = 250;
|
|
} else if (nano_sec <= 350) {
|
|
write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_350ns |
|
|
INES_INITIAL_T1_2000ns, AUXMR);
|
|
retval = 350;
|
|
} else {
|
|
write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_500ns |
|
|
INES_INITIAL_T1_2000ns, AUXMR);
|
|
retval = 500;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static inline unsigned short num_in_fifo_bytes(struct ines_priv *ines_priv)
|
|
{
|
|
return ines_inb(ines_priv, IN_FIFO_COUNT);
|
|
}
|
|
|
|
static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, u8 *buffer,
|
|
size_t length, size_t *nbytes)
|
|
{
|
|
ssize_t retval = 0;
|
|
unsigned int num_fifo_bytes, i;
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
*nbytes = 0;
|
|
while (*nbytes < length) {
|
|
if (wait_event_interruptible(board->wait,
|
|
num_in_fifo_bytes(ines_priv) ||
|
|
test_bit(RECEIVED_END_BN, &nec_priv->state) ||
|
|
test_bit(DEV_CLEAR_BN, &nec_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, &nec_priv->state))
|
|
return -EINTR;
|
|
|
|
num_fifo_bytes = num_in_fifo_bytes(ines_priv);
|
|
if (num_fifo_bytes + *nbytes > length)
|
|
num_fifo_bytes = length - *nbytes;
|
|
|
|
for (i = 0; i < num_fifo_bytes; i++)
|
|
buffer[(*nbytes)++] = read_byte(nec_priv, DIR);
|
|
if (test_bit(RECEIVED_END_BN, &nec_priv->state) &&
|
|
num_in_fifo_bytes(ines_priv) == 0)
|
|
break;
|
|
if (need_resched())
|
|
schedule();
|
|
}
|
|
/* make sure RECEIVED_END is in sync */
|
|
ines_interrupt(board);
|
|
return retval;
|
|
}
|
|
|
|
static int ines_accel_read(struct gpib_board *board, u8 *buffer,
|
|
size_t length, int *end, size_t *bytes_read)
|
|
{
|
|
ssize_t retval = 0;
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
int counter_setting;
|
|
|
|
*end = 0;
|
|
*bytes_read = 0;
|
|
if (length == 0)
|
|
return 0;
|
|
|
|
clear_bit(DEV_CLEAR_BN, &nec_priv->state);
|
|
|
|
write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR);
|
|
|
|
// clear in fifo
|
|
nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, 0);
|
|
nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, IN_FIFO_ENABLE_BIT);
|
|
|
|
ines_priv->extend_mode_bits |= LAST_BYTE_HANDLING_BIT;
|
|
ines_priv->extend_mode_bits &= ~XFER_COUNTER_OUTPUT_BIT & ~XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
|
|
counter_setting = length - num_in_fifo_bytes(ines_priv);
|
|
if (counter_setting > 0) {
|
|
ines_set_xfer_counter(ines_priv, length);
|
|
ines_priv->extend_mode_bits |= XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
|
|
// holdoff on END
|
|
nec7210_set_handshake_mode(board, nec_priv, HR_HLDE);
|
|
/* release rfd holdoff */
|
|
write_byte(nec_priv, AUX_FH, AUXMR);
|
|
}
|
|
|
|
retval = pio_read(board, ines_priv, buffer, length, bytes_read);
|
|
ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
if (retval < 0) {
|
|
write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR);
|
|
return retval;
|
|
}
|
|
if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state))
|
|
*end = 1;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static const int out_fifo_size = 0xff;
|
|
|
|
static inline unsigned short num_out_fifo_bytes(struct ines_priv *ines_priv)
|
|
{
|
|
return ines_inb(ines_priv, OUT_FIFO_COUNT);
|
|
}
|
|
|
|
static int ines_write_wait(struct gpib_board *board, struct ines_priv *ines_priv,
|
|
unsigned int fifo_threshold)
|
|
{
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
// wait until byte is ready to be sent
|
|
if (wait_event_interruptible(board->wait,
|
|
num_out_fifo_bytes(ines_priv) < fifo_threshold ||
|
|
test_bit(BUS_ERROR_BN, &nec_priv->state) ||
|
|
test_bit(DEV_CLEAR_BN, &nec_priv->state) ||
|
|
test_bit(TIMO_NUM, &board->status)))
|
|
return -ERESTARTSYS;
|
|
|
|
if (test_bit(BUS_ERROR_BN, &nec_priv->state))
|
|
return -EIO;
|
|
if (test_bit(DEV_CLEAR_BN, &nec_priv->state))
|
|
return -EINTR;
|
|
if (test_bit(TIMO_NUM, &board->status))
|
|
return -ETIMEDOUT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_accel_write(struct gpib_board *board, u8 *buffer, size_t length,
|
|
int send_eoi, size_t *bytes_written)
|
|
{
|
|
size_t count = 0;
|
|
ssize_t retval = 0;
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
unsigned int num_bytes, i;
|
|
|
|
*bytes_written = 0;
|
|
// clear out fifo
|
|
nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, 0);
|
|
nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, OUT_FIFO_ENABLE_BIT);
|
|
|
|
ines_priv->extend_mode_bits |= XFER_COUNTER_OUTPUT_BIT;
|
|
ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT;
|
|
ines_priv->extend_mode_bits &= ~LAST_BYTE_HANDLING_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
|
|
ines_set_xfer_counter(ines_priv, length);
|
|
if (send_eoi)
|
|
ines_priv->extend_mode_bits |= LAST_BYTE_HANDLING_BIT;
|
|
ines_priv->extend_mode_bits |= XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
|
|
while (count < length) {
|
|
retval = ines_write_wait(board, ines_priv, out_fifo_size);
|
|
if (retval < 0)
|
|
break;
|
|
|
|
num_bytes = out_fifo_size - num_out_fifo_bytes(ines_priv);
|
|
if (num_bytes + count > length)
|
|
num_bytes = length - count;
|
|
for (i = 0; i < num_bytes; i++)
|
|
write_byte(nec_priv, buffer[count++], CDOR);
|
|
}
|
|
if (retval < 0) {
|
|
ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
*bytes_written = length - num_out_fifo_bytes(ines_priv);
|
|
return retval;
|
|
}
|
|
// wait last byte has been sent
|
|
retval = ines_write_wait(board, ines_priv, 1);
|
|
ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
*bytes_written = length - num_out_fifo_bytes(ines_priv);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static irqreturn_t ines_pci_interrupt(int irq, void *arg)
|
|
{
|
|
struct gpib_board *board = arg;
|
|
struct ines_priv *priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
|
|
|
|
if (priv->pci_chip_type == PCI_CHIP_QUANCOM) {
|
|
if ((inb(nec_priv->iobase +
|
|
QUANCOM_IRQ_CONTROL_STATUS_REG) &
|
|
QUANCOM_IRQ_ASSERTED_BIT))
|
|
outb(QUANCOM_IRQ_ENABLE_BIT, nec_priv->iobase +
|
|
QUANCOM_IRQ_CONTROL_STATUS_REG);
|
|
}
|
|
|
|
return ines_interrupt(board);
|
|
}
|
|
|
|
static irqreturn_t ines_interrupt(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
|
|
unsigned int isr3_bits, isr4_bits;
|
|
unsigned long flags;
|
|
int wake = 0;
|
|
|
|
spin_lock_irqsave(&board->spinlock, flags);
|
|
|
|
nec7210_interrupt(board, nec_priv);
|
|
isr3_bits = ines_inb(priv, ISR3);
|
|
isr4_bits = ines_inb(priv, ISR4);
|
|
if (isr3_bits & IFC_ACTIVE_BIT) {
|
|
push_gpib_event(board, EVENT_IFC);
|
|
wake++;
|
|
}
|
|
if (isr3_bits & FIFO_ERROR_BIT)
|
|
dev_err(board->gpib_dev, "fifo error\n");
|
|
if (isr3_bits & XFER_COUNT_BIT)
|
|
wake++;
|
|
|
|
if (isr4_bits & (IN_FIFO_WATERMARK_BIT | IN_FIFO_FULL_BIT | OUT_FIFO_WATERMARK_BIT |
|
|
OUT_FIFO_EMPTY_BIT))
|
|
wake++;
|
|
|
|
if (wake)
|
|
wake_up_interruptible(&board->wait);
|
|
spin_unlock_irqrestore(&board->spinlock, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config);
|
|
static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config);
|
|
static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config);
|
|
|
|
static void ines_pci_detach(struct gpib_board *board);
|
|
static void ines_isa_detach(struct gpib_board *board);
|
|
|
|
enum ines_pci_vendor_ids {
|
|
PCI_VENDOR_ID_INES_QUICKLOGIC = 0x16da
|
|
};
|
|
|
|
enum ines_pci_device_ids {
|
|
PCI_DEVICE_ID_INES_GPIB_AMCC = 0x8507,
|
|
PCI_DEVICE_ID_INES_GPIB_QL5030 = 0x11,
|
|
};
|
|
|
|
enum ines_pci_subdevice_ids {
|
|
PCI_SUBDEVICE_ID_INES_GPIB = 0x1072
|
|
};
|
|
|
|
static struct pci_device_id ines_pci_table[] = {
|
|
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX,
|
|
PCI_SUBDEVICE_ID_INES_GPIB, 0, 0, 0},
|
|
{PCI_VENDOR_ID_AMCC, PCI_DEVICE_ID_INES_GPIB_AMCC, PCI_VENDOR_ID_AMCC,
|
|
PCI_SUBDEVICE_ID_INES_GPIB, 0, 0, 0},
|
|
{PCI_VENDOR_ID_INES_QUICKLOGIC, PCI_DEVICE_ID_INES_GPIB_QL5030,
|
|
PCI_VENDOR_ID_INES_QUICKLOGIC, PCI_DEVICE_ID_INES_GPIB_QL5030, 0, 0, 0},
|
|
{PCI_DEVICE(PCI_VENDOR_ID_QUANCOM, PCI_DEVICE_ID_QUANCOM_GPIB)},
|
|
{0}
|
|
};
|
|
MODULE_DEVICE_TABLE(pci, ines_pci_table);
|
|
|
|
struct ines_pci_id {
|
|
unsigned int vendor_id;
|
|
unsigned int device_id;
|
|
int subsystem_vendor_id;
|
|
int subsystem_device_id;
|
|
unsigned int gpib_region;
|
|
unsigned int io_offset;
|
|
enum ines_pci_chip pci_chip_type;
|
|
};
|
|
|
|
static struct ines_pci_id pci_ids[] = {
|
|
{.vendor_id = PCI_VENDOR_ID_PLX,
|
|
.device_id = PCI_DEVICE_ID_PLX_9050,
|
|
.subsystem_vendor_id = PCI_VENDOR_ID_PLX,
|
|
.subsystem_device_id = PCI_SUBDEVICE_ID_INES_GPIB,
|
|
.gpib_region = 2,
|
|
.io_offset = 1,
|
|
.pci_chip_type = PCI_CHIP_PLX9050,
|
|
},
|
|
{.vendor_id = PCI_VENDOR_ID_AMCC,
|
|
.device_id = PCI_DEVICE_ID_INES_GPIB_AMCC,
|
|
.subsystem_vendor_id = PCI_VENDOR_ID_AMCC,
|
|
.subsystem_device_id = PCI_SUBDEVICE_ID_INES_GPIB,
|
|
.gpib_region = 1,
|
|
.io_offset = 1,
|
|
.pci_chip_type = PCI_CHIP_AMCC5920,
|
|
},
|
|
{.vendor_id = PCI_VENDOR_ID_INES_QUICKLOGIC,
|
|
.device_id = PCI_DEVICE_ID_INES_GPIB_QL5030,
|
|
.subsystem_vendor_id = PCI_VENDOR_ID_INES_QUICKLOGIC,
|
|
.subsystem_device_id = PCI_DEVICE_ID_INES_GPIB_QL5030,
|
|
.gpib_region = 1,
|
|
.io_offset = 1,
|
|
.pci_chip_type = PCI_CHIP_QUICKLOGIC5030,
|
|
},
|
|
{.vendor_id = PCI_VENDOR_ID_QUANCOM,
|
|
.device_id = PCI_DEVICE_ID_QUANCOM_GPIB,
|
|
.subsystem_vendor_id = -1,
|
|
.subsystem_device_id = -1,
|
|
.gpib_region = 0,
|
|
.io_offset = 4,
|
|
.pci_chip_type = PCI_CHIP_QUANCOM,
|
|
},
|
|
};
|
|
|
|
static const int num_pci_chips = ARRAY_SIZE(pci_ids);
|
|
|
|
// wrappers for interface functions
|
|
static int ines_read(struct gpib_board *board, u8 *buffer, size_t length,
|
|
int *end, size_t *bytes_read)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
|
|
ssize_t retval;
|
|
int dummy;
|
|
|
|
retval = nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
|
|
if (retval < 0) {
|
|
write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR);
|
|
|
|
set_bit(RFD_HOLDOFF_BN, &nec_priv->state);
|
|
|
|
nec7210_read_data_in(board, nec_priv, &dummy);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static int ines_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
|
|
size_t *bytes_written)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
|
|
}
|
|
|
|
static int ines_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written);
|
|
}
|
|
|
|
static int ines_take_control(struct gpib_board *board, int synchronous)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_take_control(board, &priv->nec7210_priv, synchronous);
|
|
}
|
|
|
|
static int ines_go_to_standby(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_go_to_standby(board, &priv->nec7210_priv);
|
|
}
|
|
|
|
static int ines_request_system_control(struct gpib_board *board, int request_control)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
|
|
}
|
|
|
|
static void ines_interface_clear(struct gpib_board *board, int assert)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_interface_clear(board, &priv->nec7210_priv, assert);
|
|
}
|
|
|
|
static void ines_remote_enable(struct gpib_board *board, int enable)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
|
|
}
|
|
|
|
static int ines_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits);
|
|
}
|
|
|
|
static void ines_disable_eos(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_disable_eos(board, &priv->nec7210_priv);
|
|
}
|
|
|
|
static unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_update_status(board, &priv->nec7210_priv, clear_mask);
|
|
}
|
|
|
|
static int ines_primary_address(struct gpib_board *board, unsigned int address)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_primary_address(board, &priv->nec7210_priv, address);
|
|
}
|
|
|
|
static int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
|
|
}
|
|
|
|
static int ines_parallel_poll(struct gpib_board *board, u8 *result)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
|
|
}
|
|
|
|
static void ines_parallel_poll_configure(struct gpib_board *board, u8 config)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config);
|
|
}
|
|
|
|
static void ines_parallel_poll_response(struct gpib_board *board, int ist)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
|
|
}
|
|
|
|
static void ines_serial_poll_response(struct gpib_board *board, u8 status)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
|
|
}
|
|
|
|
static u8 ines_serial_poll_status(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
return nec7210_serial_poll_status(board, &priv->nec7210_priv);
|
|
}
|
|
|
|
static void ines_return_to_local(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv = board->private_data;
|
|
|
|
nec7210_return_to_local(board, &priv->nec7210_priv);
|
|
}
|
|
|
|
static struct gpib_interface ines_pci_unaccel_interface = {
|
|
.name = "ines_pci_unaccel",
|
|
.attach = ines_pci_attach,
|
|
.detach = ines_pci_detach,
|
|
.read = ines_read,
|
|
.write = ines_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static struct gpib_interface ines_pci_interface = {
|
|
.name = "ines_pci",
|
|
.attach = ines_pci_accel_attach,
|
|
.detach = ines_pci_detach,
|
|
.read = ines_accel_read,
|
|
.write = ines_accel_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static struct gpib_interface ines_pci_accel_interface = {
|
|
.name = "ines_pci_accel",
|
|
.attach = ines_pci_accel_attach,
|
|
.detach = ines_pci_detach,
|
|
.read = ines_accel_read,
|
|
.write = ines_accel_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static struct gpib_interface ines_isa_interface = {
|
|
.name = "ines_isa",
|
|
.attach = ines_isa_attach,
|
|
.detach = ines_isa_detach,
|
|
.read = ines_accel_read,
|
|
.write = ines_accel_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static int ines_allocate_private(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *priv;
|
|
|
|
board->private_data = kzalloc_obj(struct ines_priv);
|
|
if (!board->private_data)
|
|
return -ENOMEM;
|
|
priv = board->private_data;
|
|
init_nec7210_private(&priv->nec7210_priv);
|
|
return 0;
|
|
}
|
|
|
|
static void ines_free_private(struct gpib_board *board)
|
|
{
|
|
kfree(board->private_data);
|
|
board->private_data = NULL;
|
|
}
|
|
|
|
static int ines_generic_attach(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
struct nec7210_priv *nec_priv;
|
|
int retval;
|
|
|
|
board->status = 0;
|
|
|
|
retval = ines_allocate_private(board);
|
|
if (retval)
|
|
return retval;
|
|
ines_priv = board->private_data;
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
nec_priv->read_byte = nec7210_ioport_read_byte;
|
|
nec_priv->write_byte = nec7210_ioport_write_byte;
|
|
nec_priv->offset = 1;
|
|
nec_priv->type = IGPIB7210;
|
|
ines_priv->pci_chip_type = PCI_CHIP_NONE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, int use_accel)
|
|
{
|
|
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
/* ines doesn't seem to use internal count register */
|
|
write_byte(nec_priv, ICR | 0, AUXMR);
|
|
|
|
write_byte(nec_priv, INES_AUX_XMODE, AUXMR);
|
|
write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR);
|
|
|
|
set_bit(RFD_HOLDOFF_BN, &nec_priv->state);
|
|
|
|
write_byte(nec_priv, INES_AUXD | 0, AUXMR);
|
|
ines_outb(ines_priv, 0, XDMA_CONTROL);
|
|
ines_priv->extend_mode_bits = 0;
|
|
ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE);
|
|
if (use_accel) {
|
|
ines_outb(ines_priv, 0x80, OUT_FIFO_WATERMARK);
|
|
ines_outb(ines_priv, 0x80, IN_FIFO_WATERMARK);
|
|
ines_outb(ines_priv, IFC_ACTIVE_BIT | ATN_ACTIVE_BIT |
|
|
FIFO_ERROR_BIT | XFER_COUNT_BIT, IMR3);
|
|
ines_outb(ines_priv, IN_FIFO_WATERMARK_BIT | IN_FIFO_FULL_BIT |
|
|
OUT_FIFO_WATERMARK_BIT | OUT_FIFO_EMPTY_BIT, IMR4);
|
|
} else {
|
|
nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT | OUT_FIFO_ENABLE_BIT, 0);
|
|
ines_outb(ines_priv, IFC_ACTIVE_BIT | FIFO_ERROR_BIT, IMR3);
|
|
ines_outb(ines_priv, 0, IMR4);
|
|
}
|
|
|
|
nec7210_board_online(nec_priv, board);
|
|
if (use_accel)
|
|
nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, 0);
|
|
}
|
|
|
|
static int ines_common_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
struct nec7210_priv *nec_priv;
|
|
int isr_flags = 0;
|
|
int retval;
|
|
struct ines_pci_id found_id;
|
|
unsigned int i;
|
|
struct pci_dev *pdev;
|
|
|
|
memset(&found_id, 0, sizeof(found_id));
|
|
|
|
retval = ines_generic_attach(board);
|
|
if (retval)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
// find board
|
|
ines_priv->pci_device = NULL;
|
|
for (i = 0; i < num_pci_chips && !ines_priv->pci_device; i++) {
|
|
pdev = NULL;
|
|
do {
|
|
if (pci_ids[i].subsystem_vendor_id >= 0 &&
|
|
pci_ids[i].subsystem_device_id >= 0)
|
|
pdev = pci_get_subsys(pci_ids[i].vendor_id, pci_ids[i].device_id,
|
|
pci_ids[i].subsystem_vendor_id,
|
|
pci_ids[i].subsystem_device_id, pdev);
|
|
else
|
|
pdev = pci_get_device(pci_ids[i].vendor_id, pci_ids[i].device_id,
|
|
pdev);
|
|
if (!pdev)
|
|
break;
|
|
if (config->pci_bus >= 0 && config->pci_bus != pdev->bus->number)
|
|
continue;
|
|
if (config->pci_slot >= 0 && config->pci_slot != PCI_SLOT(pdev->devfn))
|
|
continue;
|
|
found_id = pci_ids[i];
|
|
ines_priv->pci_device = pdev;
|
|
break;
|
|
} while (1);
|
|
}
|
|
if (!ines_priv->pci_device) {
|
|
dev_err(board->gpib_dev, "could not find ines PCI board\n");
|
|
return -1;
|
|
}
|
|
|
|
if (pci_enable_device(ines_priv->pci_device)) {
|
|
dev_err(board->gpib_dev, "error enabling pci device\n");
|
|
return -1;
|
|
}
|
|
|
|
if (pci_request_regions(ines_priv->pci_device, DRV_NAME))
|
|
return -1;
|
|
nec_priv->iobase = pci_resource_start(ines_priv->pci_device,
|
|
found_id.gpib_region);
|
|
|
|
ines_priv->pci_chip_type = found_id.pci_chip_type;
|
|
nec_priv->offset = found_id.io_offset;
|
|
switch (ines_priv->pci_chip_type) {
|
|
case PCI_CHIP_PLX9050:
|
|
ines_priv->plx_iobase = pci_resource_start(ines_priv->pci_device, 1);
|
|
break;
|
|
case PCI_CHIP_AMCC5920:
|
|
ines_priv->amcc_iobase = pci_resource_start(ines_priv->pci_device, 0);
|
|
break;
|
|
case PCI_CHIP_QUANCOM:
|
|
break;
|
|
case PCI_CHIP_QUICKLOGIC5030:
|
|
break;
|
|
default:
|
|
dev_err(board->gpib_dev, "unspecified chip type? (bug)\n");
|
|
nec_priv->iobase = 0;
|
|
pci_release_regions(ines_priv->pci_device);
|
|
return -1;
|
|
}
|
|
|
|
nec7210_board_reset(nec_priv, board);
|
|
#ifdef QUANCOM_PCI
|
|
if (ines_priv->pci_chip_type == PCI_CHIP_QUANCOM) {
|
|
/* change interrupt polarity */
|
|
nec_priv->auxb_bits |= HR_INV;
|
|
ines_outb(ines_priv, nec_priv->auxb_bits, AUXMR);
|
|
}
|
|
#endif
|
|
isr_flags |= IRQF_SHARED;
|
|
if (request_irq(ines_priv->pci_device->irq, ines_pci_interrupt, isr_flags,
|
|
DRV_NAME, board)) {
|
|
dev_err(board->gpib_dev, "can't request IRQ %d\n", ines_priv->pci_device->irq);
|
|
return -1;
|
|
}
|
|
ines_priv->irq = ines_priv->pci_device->irq;
|
|
|
|
// enable interrupts on pci chip
|
|
switch (ines_priv->pci_chip_type) {
|
|
case PCI_CHIP_PLX9050:
|
|
outl(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR1_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT,
|
|
ines_priv->plx_iobase + PLX9050_INTCSR_REG);
|
|
break;
|
|
case PCI_CHIP_AMCC5920:
|
|
{
|
|
static const int region = 1;
|
|
static const int num_wait_states = 7;
|
|
u32 bits;
|
|
|
|
bits = amcc_prefetch_bits(region, PREFETCH_DISABLED);
|
|
bits |= amcc_PTADR_mode_bit(region);
|
|
bits |= amcc_disable_write_fifo_bit(region);
|
|
bits |= amcc_wait_state_bits(region, num_wait_states);
|
|
outl(bits, ines_priv->amcc_iobase + AMCC_PASS_THRU_REG);
|
|
outl(AMCC_ADDON_INTR_ENABLE_BIT, ines_priv->amcc_iobase + AMCC_INTCS_REG);
|
|
}
|
|
break;
|
|
case PCI_CHIP_QUANCOM:
|
|
outb(QUANCOM_IRQ_ENABLE_BIT, nec_priv->iobase +
|
|
QUANCOM_IRQ_CONTROL_STATUS_REG);
|
|
break;
|
|
case PCI_CHIP_QUICKLOGIC5030:
|
|
break;
|
|
default:
|
|
dev_err(board->gpib_dev, "unspecified chip type? (bug)\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
int retval;
|
|
|
|
retval = ines_common_pci_attach(board, config);
|
|
if (retval < 0)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
ines_online(ines_priv, board, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
int retval;
|
|
|
|
retval = ines_common_pci_attach(board, config);
|
|
if (retval < 0)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
ines_online(ines_priv, board, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const int ines_isa_iosize = 0x20;
|
|
|
|
static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
struct nec7210_priv *nec_priv;
|
|
int isr_flags = 0;
|
|
int retval;
|
|
|
|
retval = ines_generic_attach(board);
|
|
if (retval)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
if (!request_region(config->ibbase, ines_isa_iosize, DRV_NAME)) {
|
|
dev_err(board->gpib_dev, "ioports at 0x%x already in use\n",
|
|
config->ibbase);
|
|
return -EBUSY;
|
|
}
|
|
nec_priv->iobase = config->ibbase;
|
|
nec_priv->offset = 1;
|
|
nec7210_board_reset(nec_priv, board);
|
|
if (request_irq(config->ibirq, ines_pci_interrupt, isr_flags, DRV_NAME, board)) {
|
|
dev_err(board->gpib_dev, "failed to allocate IRQ %d\n", config->ibirq);
|
|
return -1;
|
|
}
|
|
ines_priv->irq = config->ibirq;
|
|
ines_online(ines_priv, board, 1);
|
|
return 0;
|
|
}
|
|
|
|
static void ines_pci_detach(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv;
|
|
|
|
if (ines_priv) {
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
if (ines_priv->irq) {
|
|
// disable interrupts
|
|
switch (ines_priv->pci_chip_type) {
|
|
case PCI_CHIP_AMCC5920:
|
|
if (ines_priv->plx_iobase)
|
|
outl(0, ines_priv->plx_iobase + PLX9050_INTCSR_REG);
|
|
break;
|
|
case PCI_CHIP_QUANCOM:
|
|
if (nec_priv->iobase)
|
|
outb(0, nec_priv->iobase +
|
|
QUANCOM_IRQ_CONTROL_STATUS_REG);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
free_irq(ines_priv->irq, board);
|
|
}
|
|
if (nec_priv->iobase) {
|
|
nec7210_board_reset(nec_priv, board);
|
|
pci_release_regions(ines_priv->pci_device);
|
|
}
|
|
if (ines_priv->pci_device)
|
|
pci_dev_put(ines_priv->pci_device);
|
|
}
|
|
ines_free_private(board);
|
|
}
|
|
|
|
static void ines_isa_detach(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv;
|
|
|
|
if (ines_priv) {
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
if (ines_priv->irq)
|
|
free_irq(ines_priv->irq, board);
|
|
if (nec_priv->iobase) {
|
|
nec7210_board_reset(nec_priv, board);
|
|
release_region(nec_priv->iobase, ines_isa_iosize);
|
|
}
|
|
}
|
|
ines_free_private(board);
|
|
}
|
|
|
|
static int ines_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static struct pci_driver ines_pci_driver = {
|
|
.name = "ines_gpib",
|
|
.id_table = ines_pci_table,
|
|
.probe = &ines_pci_probe
|
|
};
|
|
|
|
#ifdef CONFIG_GPIB_PCMCIA
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/string.h>
|
|
#include <linux/timer.h>
|
|
|
|
#include <pcmcia/cistpl.h>
|
|
#include <pcmcia/ds.h>
|
|
#include <pcmcia/cisreg.h>
|
|
|
|
static const int ines_pcmcia_iosize = 0x20;
|
|
|
|
/*
|
|
* The event() function is this driver's Card Services event handler.
|
|
* It will be called by Card Services when an appropriate card status
|
|
* event is received. The config() and release() entry points are
|
|
* used to configure or release a socket, in response to card insertion
|
|
* and ejection events. They are invoked from the gpib event
|
|
* handler.
|
|
*/
|
|
|
|
static int ines_gpib_config(struct pcmcia_device *link);
|
|
static void ines_gpib_release(struct pcmcia_device *link);
|
|
static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config);
|
|
static int ines_pcmcia_accel_attach(struct gpib_board *board,
|
|
const struct gpib_board_config *config);
|
|
static void ines_pcmcia_detach(struct gpib_board *board);
|
|
static int ines_common_pcmcia_attach(struct gpib_board *board);
|
|
/*
|
|
* A linked list of "instances" of the gpib device. Each actual
|
|
* PCMCIA card corresponds to one device instance, and is described
|
|
* by one dev_link_t structure (defined in ds.h).
|
|
*
|
|
* You may not want to use a linked list for this -- for example, the
|
|
* memory card driver uses an array of dev_link_t pointers, where minor
|
|
* device numbers are used to derive the corresponding array index.
|
|
*/
|
|
|
|
static struct pcmcia_device *curr_dev;
|
|
|
|
/*
|
|
* A dev_link_t structure has fields for most things that are needed
|
|
* to keep track of a socket, but there will usually be some device
|
|
* specific information that also needs to be kept track of. The
|
|
* 'priv' pointer in a dev_link_t structure can be used to point to
|
|
* a device-specific private data structure, like this.
|
|
*
|
|
* A driver needs to provide a dev_node_t structure for each device
|
|
* on a card. In some cases, there is only one device per card (for
|
|
* example, ethernet cards, modems). In other cases, there may be
|
|
* many actual or logical devices (SCSI adapters, memory cards with
|
|
* multiple partitions). The dev_node_t structures need to be kept
|
|
* in a linked list starting at the 'dev' field of a dev_link_t
|
|
* structure. We allocate them in the card's private data structure,
|
|
* because they generally can't be allocated dynamically.
|
|
*/
|
|
|
|
struct local_info {
|
|
struct pcmcia_device *p_dev;
|
|
struct gpib_board *dev;
|
|
u_short manfid;
|
|
u_short cardid;
|
|
};
|
|
|
|
/*
|
|
* gpib_attach() creates an "instance" of the driver, allocating
|
|
* local data structures for one device. The device is registered
|
|
* with Card Services.
|
|
*
|
|
* The dev_link structure is initialized, but we don't actually
|
|
* configure the card at this point -- we wait until we receive a
|
|
* card insertion event.
|
|
*/
|
|
static int ines_gpib_probe(struct pcmcia_device *link)
|
|
{
|
|
struct local_info *info;
|
|
|
|
// int ret, i;
|
|
|
|
/* Allocate space for private device-specific data */
|
|
info = kzalloc_obj(*info);
|
|
if (!info)
|
|
return -ENOMEM;
|
|
|
|
info->p_dev = link;
|
|
link->priv = info;
|
|
|
|
/* The io structure describes IO port mapping */
|
|
link->resource[0]->end = 32;
|
|
link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
|
|
link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
|
|
link->io_lines = 5;
|
|
|
|
/* General socket configuration */
|
|
link->config_flags = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
|
|
|
|
/* Register with Card Services */
|
|
curr_dev = link;
|
|
return ines_gpib_config(link);
|
|
}
|
|
|
|
/*
|
|
* This deletes a driver "instance". The device is de-registered
|
|
* with Card Services. If it has been released, all local data
|
|
* structures are freed. Otherwise, the structures will be freed
|
|
* when the device is released.
|
|
*/
|
|
static void ines_gpib_remove(struct pcmcia_device *link)
|
|
{
|
|
struct local_info *info = link->priv;
|
|
//struct struct gpib_board *dev = info->dev;
|
|
|
|
if (info->dev)
|
|
ines_pcmcia_detach(info->dev);
|
|
ines_gpib_release(link);
|
|
|
|
//free_netdev(dev);
|
|
kfree(info);
|
|
}
|
|
|
|
static int ines_gpib_config_iteration(struct pcmcia_device *link, void *priv_data)
|
|
{
|
|
return pcmcia_request_io(link);
|
|
}
|
|
|
|
/*
|
|
* gpib_config() is scheduled to run after a CARD_INSERTION event
|
|
* is received, to configure the PCMCIA socket, and to make the
|
|
* device available to the system.
|
|
*/
|
|
static int ines_gpib_config(struct pcmcia_device *link)
|
|
{
|
|
int retval;
|
|
void __iomem *virt;
|
|
|
|
retval = pcmcia_loop_config(link, &ines_gpib_config_iteration, NULL);
|
|
if (retval) {
|
|
dev_warn(&link->dev, "no configuration found\n");
|
|
ines_gpib_release(link);
|
|
return -ENODEV;
|
|
}
|
|
|
|
dev_dbg(&link->dev, "ines_cs: manufacturer: 0x%x card: 0x%x\n",
|
|
link->manf_id, link->card_id);
|
|
|
|
/*
|
|
* for the ines card we have to setup the configuration registers in
|
|
* attribute memory here
|
|
*/
|
|
link->resource[2]->flags |= WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8 | WIN_ENABLE;
|
|
link->resource[2]->end = 0x1000;
|
|
retval = pcmcia_request_window(link, link->resource[2], 250);
|
|
if (retval) {
|
|
dev_warn(&link->dev, "pcmcia_request_window failed\n");
|
|
ines_gpib_release(link);
|
|
return -ENODEV;
|
|
}
|
|
retval = pcmcia_map_mem_page(link, link->resource[2], 0);
|
|
if (retval) {
|
|
dev_warn(&link->dev, "pcmcia_map_mem_page failed\n");
|
|
ines_gpib_release(link);
|
|
return -ENODEV;
|
|
}
|
|
virt = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
|
|
writeb((link->resource[2]->start >> 2) & 0xff, virt + 0xf0); // IOWindow base
|
|
iounmap(virt);
|
|
|
|
/*
|
|
* This actually configures the PCMCIA socket -- setting up
|
|
* the I/O windows and the interrupt mapping.
|
|
*/
|
|
retval = pcmcia_enable_device(link);
|
|
if (retval) {
|
|
ines_gpib_release(link);
|
|
return -ENODEV;
|
|
}
|
|
return 0;
|
|
} /* gpib_config */
|
|
|
|
/*
|
|
* After a card is removed, gpib_release() will unregister the net
|
|
* device, and release the PCMCIA configuration. If the device is
|
|
* still open, this will be postponed until it is closed.
|
|
*/
|
|
|
|
static void ines_gpib_release(struct pcmcia_device *link)
|
|
{
|
|
pcmcia_disable_device(link);
|
|
} /* gpib_release */
|
|
|
|
static int ines_gpib_suspend(struct pcmcia_device *link)
|
|
{
|
|
//struct local_info *info = link->priv;
|
|
//struct struct gpib_board *dev = info->dev;
|
|
|
|
if (link->open)
|
|
dev_err(&link->dev, "Device still open\n");
|
|
//netif_device_detach(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_gpib_resume(struct pcmcia_device *link)
|
|
{
|
|
//struct local_info_t *info = link->priv;
|
|
//struct struct gpib_board *dev = info->dev;
|
|
|
|
/*if (link->open) {
|
|
* ni_gpib_probe(dev); / really?
|
|
* //netif_device_attach(dev);
|
|
*}
|
|
*/
|
|
return ines_gpib_config(link);
|
|
}
|
|
|
|
static struct pcmcia_device_id ines_pcmcia_ids[] = {
|
|
PCMCIA_DEVICE_MANF_CARD(0x01b4, 0x4730),
|
|
PCMCIA_DEVICE_NULL
|
|
};
|
|
MODULE_DEVICE_TABLE(pcmcia, ines_pcmcia_ids);
|
|
|
|
static struct pcmcia_driver ines_gpib_cs_driver = {
|
|
.owner = THIS_MODULE,
|
|
.name = "ines_gpib_cs",
|
|
.id_table = ines_pcmcia_ids,
|
|
.probe = ines_gpib_probe,
|
|
.remove = ines_gpib_remove,
|
|
.suspend = ines_gpib_suspend,
|
|
.resume = ines_gpib_resume,
|
|
};
|
|
|
|
static void ines_pcmcia_cleanup_module(void)
|
|
{
|
|
pcmcia_unregister_driver(&ines_gpib_cs_driver);
|
|
}
|
|
|
|
static struct gpib_interface ines_pcmcia_unaccel_interface = {
|
|
.name = "ines_pcmcia_unaccel",
|
|
.attach = ines_pcmcia_attach,
|
|
.detach = ines_pcmcia_detach,
|
|
.read = ines_read,
|
|
.write = ines_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static struct gpib_interface ines_pcmcia_accel_interface = {
|
|
.name = "ines_pcmcia_accel",
|
|
.attach = ines_pcmcia_accel_attach,
|
|
.detach = ines_pcmcia_detach,
|
|
.read = ines_accel_read,
|
|
.write = ines_accel_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static struct gpib_interface ines_pcmcia_interface = {
|
|
.name = "ines_pcmcia",
|
|
.attach = ines_pcmcia_accel_attach,
|
|
.detach = ines_pcmcia_detach,
|
|
.read = ines_accel_read,
|
|
.write = ines_accel_write,
|
|
.command = ines_command,
|
|
.take_control = ines_take_control,
|
|
.go_to_standby = ines_go_to_standby,
|
|
.request_system_control = ines_request_system_control,
|
|
.interface_clear = ines_interface_clear,
|
|
.remote_enable = ines_remote_enable,
|
|
.enable_eos = ines_enable_eos,
|
|
.disable_eos = ines_disable_eos,
|
|
.parallel_poll = ines_parallel_poll,
|
|
.parallel_poll_configure = ines_parallel_poll_configure,
|
|
.parallel_poll_response = ines_parallel_poll_response,
|
|
.local_parallel_poll_mode = NULL, // XXX
|
|
.line_status = ines_line_status,
|
|
.update_status = ines_update_status,
|
|
.primary_address = ines_primary_address,
|
|
.secondary_address = ines_secondary_address,
|
|
.serial_poll_response = ines_serial_poll_response,
|
|
.serial_poll_status = ines_serial_poll_status,
|
|
.t1_delay = ines_t1_delay,
|
|
.return_to_local = ines_return_to_local,
|
|
};
|
|
|
|
static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg)
|
|
{
|
|
struct gpib_board *board = arg;
|
|
|
|
return ines_interrupt(board);
|
|
}
|
|
|
|
static int ines_common_pcmcia_attach(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
struct nec7210_priv *nec_priv;
|
|
int retval;
|
|
|
|
if (!curr_dev) {
|
|
dev_err(board->gpib_dev, "no ines pcmcia cards found\n");
|
|
return -1;
|
|
}
|
|
|
|
retval = ines_generic_attach(board);
|
|
if (retval)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
|
|
if (!request_region(curr_dev->resource[0]->start,
|
|
resource_size(curr_dev->resource[0]), DRV_NAME)) {
|
|
dev_err(board->gpib_dev, "ioports at 0x%lx already in use\n",
|
|
(unsigned long)(curr_dev->resource[0]->start));
|
|
return -1;
|
|
}
|
|
|
|
nec_priv->iobase = curr_dev->resource[0]->start;
|
|
|
|
nec7210_board_reset(nec_priv, board);
|
|
|
|
if (request_irq(curr_dev->irq, ines_pcmcia_interrupt, IRQF_SHARED,
|
|
"pcmcia-gpib", board)) {
|
|
dev_err(board->gpib_dev, "can't request IRQ %d\n", curr_dev->irq);
|
|
return -1;
|
|
}
|
|
ines_priv->irq = curr_dev->irq;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
int retval;
|
|
|
|
retval = ines_common_pcmcia_attach(board);
|
|
if (retval < 0)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
ines_online(ines_priv, board, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ines_pcmcia_accel_attach(struct gpib_board *board,
|
|
const struct gpib_board_config *config)
|
|
{
|
|
struct ines_priv *ines_priv;
|
|
int retval;
|
|
|
|
retval = ines_common_pcmcia_attach(board);
|
|
if (retval < 0)
|
|
return retval;
|
|
|
|
ines_priv = board->private_data;
|
|
ines_online(ines_priv, board, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ines_pcmcia_detach(struct gpib_board *board)
|
|
{
|
|
struct ines_priv *ines_priv = board->private_data;
|
|
struct nec7210_priv *nec_priv;
|
|
|
|
if (ines_priv) {
|
|
nec_priv = &ines_priv->nec7210_priv;
|
|
if (ines_priv->irq)
|
|
free_irq(ines_priv->irq, board);
|
|
if (nec_priv->iobase) {
|
|
nec7210_board_reset(nec_priv, board);
|
|
release_region(nec_priv->iobase, ines_pcmcia_iosize);
|
|
}
|
|
}
|
|
ines_free_private(board);
|
|
}
|
|
|
|
#endif /* CONFIG_GPIB_PCMCIA */
|
|
|
|
static int __init ines_init_module(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = pci_register_driver(&ines_pci_driver);
|
|
if (ret) {
|
|
pr_err("pci_register_driver failed: error = %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_pci_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pci;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_pci_unaccel_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pci_unaccel;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_pci_accel_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pci_accel;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_isa_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_isa;
|
|
}
|
|
|
|
#ifdef CONFIG_GPIB_PCMCIA
|
|
ret = gpib_register_driver(&ines_pcmcia_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pcmcia;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_pcmcia_unaccel_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pcmcia_unaccel;
|
|
}
|
|
|
|
ret = gpib_register_driver(&ines_pcmcia_accel_interface, THIS_MODULE);
|
|
if (ret) {
|
|
pr_err("gpib_register_driver failed: error = %d\n", ret);
|
|
goto err_pcmcia_accel;
|
|
}
|
|
|
|
ret = pcmcia_register_driver(&ines_gpib_cs_driver);
|
|
if (ret) {
|
|
pr_err("pcmcia_register_driver failed: error = %d\n", ret);
|
|
goto err_pcmcia_driver;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
#ifdef CONFIG_GPIB_PCMCIA
|
|
err_pcmcia_driver:
|
|
gpib_unregister_driver(&ines_pcmcia_accel_interface);
|
|
err_pcmcia_accel:
|
|
gpib_unregister_driver(&ines_pcmcia_unaccel_interface);
|
|
err_pcmcia_unaccel:
|
|
gpib_unregister_driver(&ines_pcmcia_interface);
|
|
err_pcmcia:
|
|
#endif
|
|
gpib_unregister_driver(&ines_isa_interface);
|
|
err_isa:
|
|
gpib_unregister_driver(&ines_pci_accel_interface);
|
|
err_pci_accel:
|
|
gpib_unregister_driver(&ines_pci_unaccel_interface);
|
|
err_pci_unaccel:
|
|
gpib_unregister_driver(&ines_pci_interface);
|
|
err_pci:
|
|
pci_unregister_driver(&ines_pci_driver);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __exit ines_exit_module(void)
|
|
{
|
|
gpib_unregister_driver(&ines_pci_interface);
|
|
gpib_unregister_driver(&ines_pci_unaccel_interface);
|
|
gpib_unregister_driver(&ines_pci_accel_interface);
|
|
gpib_unregister_driver(&ines_isa_interface);
|
|
#ifdef CONFIG_GPIB_PCMCIA
|
|
gpib_unregister_driver(&ines_pcmcia_interface);
|
|
gpib_unregister_driver(&ines_pcmcia_unaccel_interface);
|
|
gpib_unregister_driver(&ines_pcmcia_accel_interface);
|
|
ines_pcmcia_cleanup_module();
|
|
#endif
|
|
|
|
pci_unregister_driver(&ines_pci_driver);
|
|
}
|
|
|
|
module_init(ines_init_module);
|
|
module_exit(ines_exit_module);
|