// SPDX-License-Identifier: GPL-2.0 /*************************************************************************** * National Instruments boards using tnt4882 or compatible chips (at-gpib, etc). * copyright : (C) 2001, 2002 by Frank Mori Hess ***************************************************************************/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define dev_fmt pr_fmt #define DRV_NAME KBUILD_MODNAME #include #include #include #include #include #include #include #include #include #include #include "nec7210.h" #include "gpibP.h" #include "mite.h" #include "tnt4882_registers.h" static const int ISAPNP_VENDOR_ID_NI = ISAPNP_VENDOR('N', 'I', 'C'); static const int ISAPNP_ID_NI_ATGPIB_TNT = 0xc601; enum { PCI_DEVICE_ID_NI_GPIB = 0xc801, PCI_DEVICE_ID_NI_GPIB_PLUS = 0xc811, PCI_DEVICE_ID_NI_GPIB_PLUS2 = 0x71ad, PCI_DEVICE_ID_NI_PXIGPIB = 0xc821, PCI_DEVICE_ID_NI_PMCGPIB = 0xc831, PCI_DEVICE_ID_NI_PCIEGPIB = 0x70cf, PCI_DEVICE_ID_NI_PCIE2GPIB = 0x710e, // Measurement Computing PCI-488 same design as PCI-GPIB with TNT5004 PCI_DEVICE_ID_MC_PCI488 = 0x7259, PCI_DEVICE_ID_CEC_NI_GPIB = 0x7258 }; // struct which defines private_data for tnt4882 devices struct tnt4882_priv { struct nec7210_priv nec7210_priv; struct mite_struct *mite; struct pnp_dev *pnp_dev; unsigned int irq; unsigned short imr0_bits; unsigned short imr3_bits; unsigned short auxg_bits; // bits written to auxiliary register G }; static irqreturn_t tnt4882_internal_interrupt(struct gpib_board *board); // register offset for nec7210 compatible registers static const int atgpib_reg_offset = 2; // number of ioports used static const int atgpib_iosize = 32; /* paged io */ static inline unsigned int tnt_paged_readb(struct tnt4882_priv *priv, unsigned long offset) { iowrite8(AUX_PAGEIN, priv->nec7210_priv.mmiobase + AUXMR * priv->nec7210_priv.offset); udelay(1); return ioread8(priv->nec7210_priv.mmiobase + offset); } static inline void tnt_paged_writeb(struct tnt4882_priv *priv, unsigned int value, unsigned long offset) { iowrite8(AUX_PAGEIN, priv->nec7210_priv.mmiobase + AUXMR * priv->nec7210_priv.offset); udelay(1); iowrite8(value, priv->nec7210_priv.mmiobase + offset); } /* readb/writeb wrappers */ static inline unsigned short tnt_readb(struct tnt4882_priv *priv, unsigned long offset) { void __iomem *address = priv->nec7210_priv.mmiobase + offset; unsigned long flags; unsigned short retval; spinlock_t *register_lock = &priv->nec7210_priv.register_page_lock; spin_lock_irqsave(register_lock, flags); switch (offset) { case CSR: case SASR: case ISR0: case BSR: switch (priv->nec7210_priv.type) { case TNT4882: case TNT5004: retval = ioread8(address); break; case NAT4882: retval = tnt_paged_readb(priv, offset - tnt_pagein_offset); break; case NEC7210: retval = 0; break; default: retval = 0; break; } break; default: retval = ioread8(address); break; } spin_unlock_irqrestore(register_lock, flags); return retval; } static inline void tnt_writeb(struct tnt4882_priv *priv, unsigned short value, unsigned long offset) { void __iomem *address = priv->nec7210_priv.mmiobase + offset; unsigned long flags; spinlock_t *register_lock = &priv->nec7210_priv.register_page_lock; spin_lock_irqsave(register_lock, flags); switch (offset) { case KEYREG: case IMR0: case BCR: switch (priv->nec7210_priv.type) { case TNT4882: case TNT5004: iowrite8(value, address); break; case NAT4882: tnt_paged_writeb(priv, value, offset - tnt_pagein_offset); break; case NEC7210: break; default: break; } break; default: iowrite8(value, address); break; } spin_unlock_irqrestore(register_lock, flags); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GPIB driver for National Instruments boards using tnt4882 or compatible chips"); static int tnt4882_line_status(const struct gpib_board *board) { int status = VALID_ALL; int bcsr_bits; struct tnt4882_priv *tnt_priv; tnt_priv = board->private_data; bcsr_bits = tnt_readb(tnt_priv, BSR); if (bcsr_bits & BCSR_REN_BIT) status |= BUS_REN; if (bcsr_bits & BCSR_IFC_BIT) status |= BUS_IFC; if (bcsr_bits & BCSR_SRQ_BIT) status |= BUS_SRQ; if (bcsr_bits & BCSR_EOI_BIT) status |= BUS_EOI; if (bcsr_bits & BCSR_NRFD_BIT) status |= BUS_NRFD; if (bcsr_bits & BCSR_NDAC_BIT) status |= BUS_NDAC; if (bcsr_bits & BCSR_DAV_BIT) status |= BUS_DAV; if (bcsr_bits & BCSR_ATN_BIT) status |= BUS_ATN; return status; } static int tnt4882_t1_delay(struct gpib_board *board, unsigned int nano_sec) { struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; unsigned int retval; retval = nec7210_t1_delay(board, nec_priv, nano_sec); if (nec_priv->type == NEC7210) return retval; if (nano_sec <= 350) { tnt_writeb(tnt_priv, MSTD, KEYREG); retval = 350; } else { tnt_writeb(tnt_priv, 0, KEYREG); } if (nano_sec > 500 && nano_sec <= 1100) { write_byte(nec_priv, AUXRI | USTD, AUXMR); retval = 1100; } else { write_byte(nec_priv, AUXRI, AUXMR); } return retval; } static int fifo_word_available(struct tnt4882_priv *tnt_priv) { int status2; int retval; status2 = tnt_readb(tnt_priv, STS2); retval = (status2 & AEFN) && (status2 & BEFN); return retval; } static int fifo_byte_available(struct tnt4882_priv *tnt_priv) { int status2; int retval; status2 = tnt_readb(tnt_priv, STS2); retval = (status2 & AEFN) || (status2 & BEFN); return retval; } static int fifo_xfer_done(struct tnt4882_priv *tnt_priv) { int status1; int retval; status1 = tnt_readb(tnt_priv, STS1); retval = status1 & (S_DONE | S_HALT); return retval; } static int drain_fifo_words(struct tnt4882_priv *tnt_priv, uint8_t *buffer, int num_bytes) { int count = 0; struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; while (fifo_word_available(tnt_priv) && count + 2 <= num_bytes) { short word; word = ioread16(nec_priv->mmiobase + FIFOB); buffer[count++] = word & 0xff; buffer[count++] = (word >> 8) & 0xff; } return count; } static void tnt4882_release_holdoff(struct gpib_board *board, struct tnt4882_priv *tnt_priv) { struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; unsigned short sasr_bits; sasr_bits = tnt_readb(tnt_priv, SASR); /*tnt4882 not in one-chip mode won't always release holdoff unless we * are in the right mode when release handshake command is given */ if (sasr_bits & AEHS_BIT) /* holding off due to holdoff on end mode*/ { nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); write_byte(nec_priv, AUX_FH, AUXMR); } else if (sasr_bits & ANHS1_BIT) { /* held off due to holdoff on all data mode*/ nec7210_set_handshake_mode(board, nec_priv, HR_HLDA); write_byte(nec_priv, AUX_FH, AUXMR); nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); } else { /* held off due to holdoff immediately command */ nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); write_byte(nec_priv, AUX_FH, AUXMR); } } static int tnt4882_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) { size_t count = 0; ssize_t retval = 0; struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; unsigned int bits; s32 hw_count; unsigned long flags; *bytes_read = 0; // FIXME: really, DEV_CLEAR_BN should happen elsewhere to prevent race clear_bit(DEV_CLEAR_BN, &nec_priv->state); clear_bit(ADR_CHANGE_BN, &nec_priv->state); nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, HR_ENDIE); if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); else nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); tnt_writeb(tnt_priv, nec_priv->auxa_bits | HR_HLDA, CCR); bits = TNT_B_16BIT | TNT_IN | TNT_CCEN; tnt_writeb(tnt_priv, bits, CFG); tnt_writeb(tnt_priv, RESET_FIFO, CMDR); udelay(1); // load 2's complement of count into hardware counters hw_count = -length; tnt_writeb(tnt_priv, hw_count & 0xff, CNT0); tnt_writeb(tnt_priv, (hw_count >> 8) & 0xff, CNT1); tnt_writeb(tnt_priv, (hw_count >> 16) & 0xff, CNT2); tnt_writeb(tnt_priv, (hw_count >> 24) & 0xff, CNT3); tnt4882_release_holdoff(board, tnt_priv); tnt_writeb(tnt_priv, GO, CMDR); udelay(1); spin_lock_irqsave(&board->spinlock, flags); tnt_priv->imr3_bits |= HR_DONE | HR_NEF; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); spin_unlock_irqrestore(&board->spinlock, flags); while (count + 2 <= length && test_bit(RECEIVED_END_BN, &nec_priv->state) == 0 && fifo_xfer_done(tnt_priv) == 0) { // wait until a word is ready if (wait_event_interruptible(board->wait, fifo_word_available(tnt_priv) || fifo_xfer_done(tnt_priv) || test_bit(RECEIVED_END_BN, &nec_priv->state) || test_bit(DEV_CLEAR_BN, &nec_priv->state) || test_bit(ADR_CHANGE_BN, &nec_priv->state) || test_bit(TIMO_NUM, &board->status))) { retval = -ERESTARTSYS; break; } if (test_bit(TIMO_NUM, &board->status)) { retval = -ETIMEDOUT; break; } if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) { retval = -EINTR; break; } if (test_bit(ADR_CHANGE_BN, &nec_priv->state)) { retval = -EINTR; break; } spin_lock_irqsave(&board->spinlock, flags); count += drain_fifo_words(tnt_priv, &buffer[count], length - count); tnt_priv->imr3_bits |= HR_NEF; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); spin_unlock_irqrestore(&board->spinlock, flags); if (need_resched()) schedule(); } // wait for last byte if (count < length) { spin_lock_irqsave(&board->spinlock, flags); tnt_priv->imr3_bits |= HR_DONE | HR_NEF; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); spin_unlock_irqrestore(&board->spinlock, flags); if (wait_event_interruptible(board->wait, fifo_xfer_done(tnt_priv) || test_bit(RECEIVED_END_BN, &nec_priv->state) || test_bit(DEV_CLEAR_BN, &nec_priv->state) || test_bit(ADR_CHANGE_BN, &nec_priv->state) || test_bit(TIMO_NUM, &board->status))) { retval = -ERESTARTSYS; } if (test_bit(TIMO_NUM, &board->status)) retval = -ETIMEDOUT; if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) retval = -EINTR; if (test_bit(ADR_CHANGE_BN, &nec_priv->state)) retval = -EINTR; count += drain_fifo_words(tnt_priv, &buffer[count], length - count); if (fifo_byte_available(tnt_priv) && count < length) buffer[count++] = tnt_readb(tnt_priv, FIFOB); } if (count < length) tnt_writeb(tnt_priv, STOP, CMDR); udelay(1); nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, 0); nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); /* force handling of any pending interrupts (seems to be needed * to keep interrupts from getting hosed, plus for syncing * with RECEIVED_END below) */ tnt4882_internal_interrupt(board); /* RECEIVED_END should be in sync now */ if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) *end = 1; if (retval < 0) { // force immediate holdoff write_byte(nec_priv, AUX_HLDI, AUXMR); set_bit(RFD_HOLDOFF_BN, &nec_priv->state); } *bytes_read = count; return retval; } static int fifo_space_available(struct tnt4882_priv *tnt_priv) { int status2; int retval; status2 = tnt_readb(tnt_priv, STS2); retval = (status2 & AFFN) && (status2 & BFFN); return retval; } static unsigned int tnt_transfer_count(struct tnt4882_priv *tnt_priv) { unsigned int count = 0; count |= tnt_readb(tnt_priv, CNT0) & 0xff; count |= (tnt_readb(tnt_priv, CNT1) << 8) & 0xff00; count |= (tnt_readb(tnt_priv, CNT2) << 16) & 0xff0000; count |= (tnt_readb(tnt_priv, CNT3) << 24) & 0xff000000; // return two's complement return -count; }; static int write_wait(struct gpib_board *board, struct tnt4882_priv *tnt_priv, int wait_for_done, int send_commands) { struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; if (wait_event_interruptible(board->wait, (!wait_for_done && fifo_space_available(tnt_priv)) || fifo_xfer_done(tnt_priv) || 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(TIMO_NUM, &board->status)) return -ETIMEDOUT; if (test_and_clear_bit(BUS_ERROR_BN, &nec_priv->state)) return (send_commands) ? -ENOTCONN : -ECOMM; if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) return -EINTR; return 0; } static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, int send_commands, size_t *bytes_written) { size_t count = 0; ssize_t retval = 0; struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; unsigned int bits; s32 hw_count; unsigned long flags; *bytes_written = 0; // FIXME: really, DEV_CLEAR_BN should happen elsewhere to prevent race clear_bit(DEV_CLEAR_BN, &nec_priv->state); nec7210_set_reg_bits(nec_priv, IMR1, HR_ERRIE, HR_ERRIE); if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); else nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); tnt_writeb(tnt_priv, RESET_FIFO, CMDR); udelay(1); bits = TNT_B_16BIT; if (send_eoi) { bits |= TNT_CCEN; if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) tnt_writeb(tnt_priv, AUX_SEOI, CCR); } if (send_commands) bits |= TNT_COMMAND; tnt_writeb(tnt_priv, bits, CFG); // load 2's complement of count into hardware counters hw_count = -length; tnt_writeb(tnt_priv, hw_count & 0xff, CNT0); tnt_writeb(tnt_priv, (hw_count >> 8) & 0xff, CNT1); tnt_writeb(tnt_priv, (hw_count >> 16) & 0xff, CNT2); tnt_writeb(tnt_priv, (hw_count >> 24) & 0xff, CNT3); tnt_writeb(tnt_priv, GO, CMDR); udelay(1); spin_lock_irqsave(&board->spinlock, flags); tnt_priv->imr3_bits |= HR_DONE; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); spin_unlock_irqrestore(&board->spinlock, flags); while (count < length) { // wait until byte is ready to be sent retval = write_wait(board, tnt_priv, 0, send_commands); if (retval < 0) break; if (fifo_xfer_done(tnt_priv)) break; spin_lock_irqsave(&board->spinlock, flags); while (fifo_space_available(tnt_priv) && count < length) { u16 word; word = buffer[count++] & 0xff; if (count < length) word |= (buffer[count++] << 8) & 0xff00; iowrite16(word, nec_priv->mmiobase + FIFOB); } // avoid unnecessary HR_NFF interrupts // tnt_priv->imr3_bits |= HR_NFF; // tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); spin_unlock_irqrestore(&board->spinlock, flags); if (need_resched()) schedule(); } // wait last byte has been sent if (retval == 0) retval = write_wait(board, tnt_priv, 1, send_commands); tnt_writeb(tnt_priv, STOP, CMDR); udelay(1); nec7210_set_reg_bits(nec_priv, IMR1, HR_ERR, 0x0); nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0x0); /* force handling of any interrupts that happened * while they were masked (this appears to be needed) */ tnt4882_internal_interrupt(board); *bytes_written = length - tnt_transfer_count(tnt_priv); return retval; } static int tnt4882_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, size_t *bytes_written) { return generic_write(board, buffer, length, send_eoi, 0, bytes_written); } static int tnt4882_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written) { return generic_write(board, buffer, length, 0, 1, bytes_written); } static irqreturn_t tnt4882_internal_interrupt(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; int isr0_bits, isr3_bits, imr3_bits; unsigned long flags; spin_lock_irqsave(&board->spinlock, flags); nec7210_interrupt(board, &priv->nec7210_priv); isr0_bits = tnt_readb(priv, ISR0); isr3_bits = tnt_readb(priv, ISR3); imr3_bits = priv->imr3_bits; if (isr0_bits & TNT_IFCI_BIT) push_gpib_event(board, EventIFC); //XXX don't need this wakeup, one below should do? // wake_up_interruptible(&board->wait); if (isr3_bits & HR_NFF) priv->imr3_bits &= ~HR_NFF; if (isr3_bits & HR_NEF) priv->imr3_bits &= ~HR_NEF; if (isr3_bits & HR_DONE) priv->imr3_bits &= ~HR_DONE; if (isr3_bits & (HR_INTR | HR_TLCI)) { dev_dbg(board->gpib_dev, "minor %i isr0 0x%x imr0 0x%x isr3 0x%x imr3 0x%x\n", board->minor, isr0_bits, priv->imr0_bits, isr3_bits, imr3_bits); tnt_writeb(priv, priv->imr3_bits, IMR3); wake_up_interruptible(&board->wait); } spin_unlock_irqrestore(&board->spinlock, flags); return IRQ_HANDLED; } static irqreturn_t tnt4882_interrupt(int irq, void *arg) { return tnt4882_internal_interrupt(arg); } // wrappers for interface functions static int tnt4882_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) { struct tnt4882_priv *priv = board->private_data; struct nec7210_priv *nec_priv = &priv->nec7210_priv; int retval; int dummy; retval = nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); if (retval < 0) { // force immediate holdoff write_byte(nec_priv, AUX_HLDI, AUXMR); set_bit(RFD_HOLDOFF_BN, &nec_priv->state); nec7210_read_data_in(board, nec_priv, &dummy); } return retval; } static int tnt4882_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi, size_t *bytes_written) { struct tnt4882_priv *priv = board->private_data; return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); } static int tnt4882_command_unaccel(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written) { struct tnt4882_priv *priv = board->private_data; return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); } static int tnt4882_take_control(struct gpib_board *board, int synchronous) { struct tnt4882_priv *priv = board->private_data; return nec7210_take_control(board, &priv->nec7210_priv, synchronous); } static int tnt4882_go_to_standby(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; return nec7210_go_to_standby(board, &priv->nec7210_priv); } static void tnt4882_request_system_control(struct gpib_board *board, int request_control) { struct tnt4882_priv *priv = board->private_data; if (request_control) { tnt_writeb(priv, SETSC, CMDR); udelay(1); } nec7210_request_system_control(board, &priv->nec7210_priv, request_control); if (!request_control) { tnt_writeb(priv, CLRSC, CMDR); udelay(1); } } static void tnt4882_interface_clear(struct gpib_board *board, int assert) { struct tnt4882_priv *priv = board->private_data; nec7210_interface_clear(board, &priv->nec7210_priv, assert); } static void tnt4882_remote_enable(struct gpib_board *board, int enable) { struct tnt4882_priv *priv = board->private_data; nec7210_remote_enable(board, &priv->nec7210_priv, enable); } static int tnt4882_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits) { struct tnt4882_priv *priv = board->private_data; return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); } static void tnt4882_disable_eos(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; nec7210_disable_eos(board, &priv->nec7210_priv); } static unsigned int tnt4882_update_status(struct gpib_board *board, unsigned int clear_mask) { unsigned long flags; u8 line_status; struct tnt4882_priv *priv = board->private_data; spin_lock_irqsave(&board->spinlock, flags); board->status &= ~clear_mask; nec7210_update_status_nolock(board, &priv->nec7210_priv); /* set / clear SRQ state since it is not cleared by interrupt */ line_status = tnt_readb(priv, BSR); if (line_status & BCSR_SRQ_BIT) set_bit(SRQI_NUM, &board->status); else clear_bit(SRQI_NUM, &board->status); spin_unlock_irqrestore(&board->spinlock, flags); return board->status; } static int tnt4882_primary_address(struct gpib_board *board, unsigned int address) { struct tnt4882_priv *priv = board->private_data; return nec7210_primary_address(board, &priv->nec7210_priv, address); } static int tnt4882_secondary_address(struct gpib_board *board, unsigned int address, int enable) { struct tnt4882_priv *priv = board->private_data; return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); } static int tnt4882_parallel_poll(struct gpib_board *board, uint8_t *result) { struct tnt4882_priv *tnt_priv = board->private_data; if (tnt_priv->nec7210_priv.type != NEC7210) { tnt_priv->auxg_bits |= RPP2_BIT; write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); udelay(2); //FIXME use parallel poll timeout *result = read_byte(&tnt_priv->nec7210_priv, CPTR); tnt_priv->auxg_bits &= ~RPP2_BIT; write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); return 0; } else { return nec7210_parallel_poll(board, &tnt_priv->nec7210_priv, result); } } static void tnt4882_parallel_poll_configure(struct gpib_board *board, uint8_t config) { struct tnt4882_priv *priv = board->private_data; if (priv->nec7210_priv.type == TNT5004) { /* configure locally */ write_byte(&priv->nec7210_priv, AUXRI | 0x4, AUXMR); if (config) /* set response + clear sense */ write_byte(&priv->nec7210_priv, PPR | config, AUXMR); else /* disable ppoll */ write_byte(&priv->nec7210_priv, PPR | 0x10, AUXMR); } else { nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); } } static void tnt4882_parallel_poll_response(struct gpib_board *board, int ist) { struct tnt4882_priv *priv = board->private_data; nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); } /* this is just used by the old nec7210 isa interfaces, the newer * boards use tnt4882_serial_poll_response2 */ static void tnt4882_serial_poll_response(struct gpib_board *board, uint8_t status) { struct tnt4882_priv *priv = board->private_data; nec7210_serial_poll_response(board, &priv->nec7210_priv, status); } static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t status, int new_reason_for_service) { struct tnt4882_priv *priv = board->private_data; unsigned long flags; const int MSS = status & request_service_bit; const int reqt = MSS && new_reason_for_service; const int reqf = MSS == 0; spin_lock_irqsave(&board->spinlock, flags); if (reqt) { priv->nec7210_priv.srq_pending = 1; clear_bit(SPOLL_NUM, &board->status); } else { if (reqf) priv->nec7210_priv.srq_pending = 0; } if (reqt) /* It may seem like a race to issue reqt before updating * the status byte, but it is not. The chip does not * issue the reqt until the SPMR is written to at * a later time. */ write_byte(&priv->nec7210_priv, AUX_REQT, AUXMR); else if (reqf) write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR); /* We need to always zero bit 6 of the status byte before writing it to * the SPMR to insure we are using * serial poll mode SP1, and not accidentally triggering mode SP3. */ write_byte(&priv->nec7210_priv, status & ~request_service_bit, SPMR); spin_unlock_irqrestore(&board->spinlock, flags); } static uint8_t tnt4882_serial_poll_status(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; return nec7210_serial_poll_status(board, &priv->nec7210_priv); } static void tnt4882_return_to_local(struct gpib_board *board) { struct tnt4882_priv *priv = board->private_data; nec7210_return_to_local(board, &priv->nec7210_priv); } static void tnt4882_board_reset(struct tnt4882_priv *tnt_priv, struct gpib_board *board) { struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; tnt_priv->imr0_bits = 0; tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0); tnt_priv->imr3_bits = 0; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); tnt_readb(tnt_priv, IMR0); tnt_readb(tnt_priv, IMR3); nec7210_board_reset(nec_priv, board); } static int tnt4882_allocate_private(struct gpib_board *board) { struct tnt4882_priv *tnt_priv; board->private_data = kmalloc(sizeof(struct tnt4882_priv), GFP_KERNEL); if (!board->private_data) return -1; tnt_priv = board->private_data; memset(tnt_priv, 0, sizeof(struct tnt4882_priv)); init_nec7210_private(&tnt_priv->nec7210_priv); return 0; } static void tnt4882_free_private(struct gpib_board *board) { kfree(board->private_data); board->private_data = NULL; } static void tnt4882_init(struct tnt4882_priv *tnt_priv, const struct gpib_board *board) { struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; /* Turbo488 software reset */ tnt_writeb(tnt_priv, SOFT_RESET, CMDR); udelay(1); // turn off one-chip mode tnt_writeb(tnt_priv, NODMA, HSSEL); tnt_writeb(tnt_priv, 0, ACCWR); // make sure we are in 7210 mode tnt_writeb(tnt_priv, AUX_7210, AUXCR); udelay(1); // registers might be swapped, so write it to the swapped address too tnt_writeb(tnt_priv, AUX_7210, SWAPPED_AUXCR); udelay(1); // turn on one-chip mode if (nec_priv->type == TNT4882 || nec_priv->type == TNT5004) tnt_writeb(tnt_priv, NODMA | TNT_ONE_CHIP_BIT, HSSEL); else tnt_writeb(tnt_priv, NODMA, HSSEL); nec7210_board_reset(nec_priv, board); // read-clear isr0 tnt_readb(tnt_priv, ISR0); // enable passing of nat4882 interrupts tnt_priv->imr3_bits = HR_TLCI; tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); // enable interrupt tnt_writeb(tnt_priv, 0x1, INTRT); // force immediate holdoff write_byte(&tnt_priv->nec7210_priv, AUX_HLDI, AUXMR); set_bit(RFD_HOLDOFF_BN, &nec_priv->state); tnt_priv->auxg_bits = AUXRG | NTNL_BIT; write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); nec7210_board_online(nec_priv, board); // enable interface clear interrupt for event queue tnt_priv->imr0_bits = TNT_IMR0_ALWAYS_BITS | TNT_ATNI_BIT | TNT_IFCIE_BIT; tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0); } static int ni_pci_attach(struct gpib_board *board, const gpib_board_config_t *config) { struct tnt4882_priv *tnt_priv; struct nec7210_priv *nec_priv; int isr_flags = IRQF_SHARED; int retval; struct mite_struct *mite; board->status = 0; if (tnt4882_allocate_private(board)) return -ENOMEM; tnt_priv = board->private_data; nec_priv = &tnt_priv->nec7210_priv; nec_priv->type = TNT4882; nec_priv->read_byte = nec7210_locking_iomem_read_byte; nec_priv->write_byte = nec7210_locking_iomem_write_byte; nec_priv->offset = atgpib_reg_offset; if (!mite_devices) return -ENODEV; for (mite = mite_devices; mite; mite = mite->next) { short found_board; if (mite->used) continue; if (config->pci_bus >= 0 && config->pci_bus != mite->pcidev->bus->number) continue; if (config->pci_slot >= 0 && config->pci_slot != PCI_SLOT(mite->pcidev->devfn)) continue; switch (mite_device_id(mite)) { case PCI_DEVICE_ID_NI_GPIB: case PCI_DEVICE_ID_NI_GPIB_PLUS: case PCI_DEVICE_ID_NI_GPIB_PLUS2: case PCI_DEVICE_ID_NI_PXIGPIB: case PCI_DEVICE_ID_NI_PMCGPIB: case PCI_DEVICE_ID_NI_PCIEGPIB: case PCI_DEVICE_ID_NI_PCIE2GPIB: // support for Measurement Computing PCI-488 case PCI_DEVICE_ID_MC_PCI488: case PCI_DEVICE_ID_CEC_NI_GPIB: found_board = 1; break; default: found_board = 0; break; } if (found_board) break; } if (!mite) return -ENODEV; tnt_priv->mite = mite; retval = mite_setup(tnt_priv->mite); if (retval < 0) return retval; nec_priv->mmiobase = tnt_priv->mite->daq_io_addr; // get irq retval = request_irq(mite_irq(tnt_priv->mite), tnt4882_interrupt, isr_flags, "ni-pci-gpib", board); if (retval) { dev_err(board->gpib_dev, "failed to obtain pci irq %d\n", mite_irq(tnt_priv->mite)); return retval; } tnt_priv->irq = mite_irq(tnt_priv->mite); // TNT5004 detection switch (tnt_readb(tnt_priv, CSR) & 0xf0) { case 0x30: nec_priv->type = TNT4882; break; case 0x40: nec_priv->type = TNT5004; break; } tnt4882_init(tnt_priv, board); return 0; } static void ni_pci_detach(struct gpib_board *board) { struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv; if (tnt_priv) { nec_priv = &tnt_priv->nec7210_priv; if (nec_priv->mmiobase) tnt4882_board_reset(tnt_priv, board); if (tnt_priv->irq) free_irq(tnt_priv->irq, board); if (tnt_priv->mite) mite_unsetup(tnt_priv->mite); } tnt4882_free_private(board); } static int ni_isapnp_find(struct pnp_dev **dev) { *dev = pnp_find_dev(NULL, ISAPNP_VENDOR_ID_NI, ISAPNP_FUNCTION(ISAPNP_ID_NI_ATGPIB_TNT), NULL); if (!*dev || !(*dev)->card) return -ENODEV; if (pnp_device_attach(*dev) < 0) return -EBUSY; if (pnp_activate_dev(*dev) < 0) { pnp_device_detach(*dev); return -EAGAIN; } if (!pnp_port_valid(*dev, 0) || !pnp_irq_valid(*dev, 0)) { pnp_device_detach(*dev); return -EINVAL; } return 0; } static int ni_isa_attach_common(struct gpib_board *board, const gpib_board_config_t *config, enum nec7210_chipset chipset) { struct tnt4882_priv *tnt_priv; struct nec7210_priv *nec_priv; int isr_flags = 0; u32 iobase; int irq; int retval; board->status = 0; if (tnt4882_allocate_private(board)) return -ENOMEM; tnt_priv = board->private_data; nec_priv = &tnt_priv->nec7210_priv; nec_priv->type = chipset; nec_priv->read_byte = nec7210_locking_ioport_read_byte; nec_priv->write_byte = nec7210_locking_ioport_write_byte; nec_priv->offset = atgpib_reg_offset; // look for plug-n-play board if (config->ibbase == 0) { struct pnp_dev *dev; retval = ni_isapnp_find(&dev); if (retval < 0) return retval; tnt_priv->pnp_dev = dev; iobase = pnp_port_start(dev, 0); irq = pnp_irq(dev, 0); } else { iobase = config->ibbase; irq = config->ibirq; } // allocate ioports if (!request_region(iobase, atgpib_iosize, "atgpib")) return -EBUSY; nec_priv->mmiobase = ioport_map(iobase, atgpib_iosize); if (!nec_priv->mmiobase) return -EBUSY; // get irq retval = request_irq(irq, tnt4882_interrupt, isr_flags, "atgpib", board); if (retval) { dev_err(board->gpib_dev, "failed to request ISA irq %d\n", irq); return retval; } tnt_priv->irq = irq; tnt4882_init(tnt_priv, board); return 0; } static int ni_tnt_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) { return ni_isa_attach_common(board, config, TNT4882); } static int ni_nat4882_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) { return ni_isa_attach_common(board, config, NAT4882); } static int ni_nec_isa_attach(struct gpib_board *board, const gpib_board_config_t *config) { return ni_isa_attach_common(board, config, NEC7210); } static void ni_isa_detach(struct gpib_board *board) { struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv; if (tnt_priv) { nec_priv = &tnt_priv->nec7210_priv; if (nec_priv->iobase) tnt4882_board_reset(tnt_priv, board); if (tnt_priv->irq) free_irq(tnt_priv->irq, board); if (nec_priv->mmiobase) ioport_unmap(nec_priv->mmiobase); if (nec_priv->iobase) release_region(nec_priv->iobase, atgpib_iosize); if (tnt_priv->pnp_dev) pnp_device_detach(tnt_priv->pnp_dev); } tnt4882_free_private(board); } static int tnt4882_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { return 0; } static gpib_interface_t ni_pci_interface = { .name = "ni_pci", .attach = ni_pci_attach, .detach = ni_pci_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_pci_accel_interface = { .name = "ni_pci_accel", .attach = ni_pci_attach, .detach = ni_pci_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_isa_interface = { .name = "ni_isa", .attach = ni_tnt_isa_attach, .detach = ni_isa_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_nat4882_isa_interface = { .name = "ni_nat4882_isa", .attach = ni_nat4882_isa_attach, .detach = ni_isa_detach, .read = tnt4882_read, .write = tnt4882_write, .command = tnt4882_command_unaccel, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_nec_isa_interface = { .name = "ni_nec_isa", .attach = ni_nec_isa_attach, .detach = ni_isa_detach, .read = tnt4882_read, .write = tnt4882_write, .command = tnt4882_command_unaccel, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = NULL, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response = tnt4882_serial_poll_response, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_isa_accel_interface = { .name = "ni_isa_accel", .attach = ni_tnt_isa_attach, .detach = ni_isa_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_nat4882_isa_accel_interface = { .name = "ni_nat4882_isa_accel", .attach = ni_nat4882_isa_attach, .detach = ni_isa_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command_unaccel, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response2 = tnt4882_serial_poll_response2, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_nec_isa_accel_interface = { .name = "ni_nec_isa_accel", .attach = ni_nec_isa_attach, .detach = ni_isa_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command_unaccel, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = NULL, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response = tnt4882_serial_poll_response, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static const struct pci_device_id tnt4882_pci_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB_PLUS)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB_PLUS2)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PXIGPIB)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PMCGPIB)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PCIEGPIB)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PCIE2GPIB)}, // support for Measurement Computing PCI-488 {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_MC_PCI488)}, {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_CEC_NI_GPIB)}, { 0 } }; MODULE_DEVICE_TABLE(pci, tnt4882_pci_table); static struct pci_driver tnt4882_pci_driver = { .name = DRV_NAME, .id_table = tnt4882_pci_table, .probe = &tnt4882_pci_probe }; #if 0 /* unused, will be needed when the driver is turned into a pnp_driver */ static const struct pnp_device_id tnt4882_pnp_table[] = { {.id = "NICC601"}, {.id = ""} }; MODULE_DEVICE_TABLE(pnp, tnt4882_pnp_table); #endif #ifdef CONFIG_GPIB_PCMCIA static gpib_interface_t ni_pcmcia_interface; static gpib_interface_t ni_pcmcia_accel_interface; static int __init init_ni_gpib_cs(void); static void __exit exit_ni_gpib_cs(void); #endif static int __init tnt4882_init_module(void) { int result; result = pci_register_driver(&tnt4882_pci_driver); if (result) { pr_err("pci_register_driver failed: error = %d\n", result); return result; } result = gpib_register_driver(&ni_isa_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_isa; } result = gpib_register_driver(&ni_isa_accel_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_isa_accel; } result = gpib_register_driver(&ni_nat4882_isa_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_nat4882_isa; } result = gpib_register_driver(&ni_nat4882_isa_accel_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_nat4882_isa_accel; } result = gpib_register_driver(&ni_nec_isa_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_nec_isa; } result = gpib_register_driver(&ni_nec_isa_accel_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_nec_isa_accel; } result = gpib_register_driver(&ni_pci_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_pci; } result = gpib_register_driver(&ni_pci_accel_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_pci_accel; } #ifdef CONFIG_GPIB_PCMCIA result = gpib_register_driver(&ni_pcmcia_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_pcmcia; } result = gpib_register_driver(&ni_pcmcia_accel_interface, THIS_MODULE); if (result) { pr_err("gpib_register_driver failed: error = %d\n", result); goto err_pcmcia_accel; } result = init_ni_gpib_cs(); if (result) { pr_err("pcmcia_register_driver failed: error = %d\n", result); goto err_pcmcia_driver; } #endif mite_init(); return 0; #ifdef CONFIG_GPIB_PCMCIA err_pcmcia_driver: gpib_unregister_driver(&ni_pcmcia_accel_interface); err_pcmcia_accel: gpib_unregister_driver(&ni_pcmcia_interface); err_pcmcia: #endif gpib_unregister_driver(&ni_pci_accel_interface); err_pci_accel: gpib_unregister_driver(&ni_pci_interface); err_pci: gpib_unregister_driver(&ni_nec_isa_accel_interface); err_nec_isa_accel: gpib_unregister_driver(&ni_nec_isa_interface); err_nec_isa: gpib_unregister_driver(&ni_nat4882_isa_accel_interface); err_nat4882_isa_accel: gpib_unregister_driver(&ni_nat4882_isa_interface); err_nat4882_isa: gpib_unregister_driver(&ni_isa_accel_interface); err_isa_accel: gpib_unregister_driver(&ni_isa_interface); err_isa: pci_unregister_driver(&tnt4882_pci_driver); return result; } static void __exit tnt4882_exit_module(void) { gpib_unregister_driver(&ni_isa_interface); gpib_unregister_driver(&ni_isa_accel_interface); gpib_unregister_driver(&ni_nat4882_isa_interface); gpib_unregister_driver(&ni_nat4882_isa_accel_interface); gpib_unregister_driver(&ni_nec_isa_interface); gpib_unregister_driver(&ni_nec_isa_accel_interface); gpib_unregister_driver(&ni_pci_interface); gpib_unregister_driver(&ni_pci_accel_interface); #ifdef CONFIG_GPIB_PCMCIA gpib_unregister_driver(&ni_pcmcia_interface); gpib_unregister_driver(&ni_pcmcia_accel_interface); exit_ni_gpib_cs(); #endif mite_cleanup(); pci_unregister_driver(&tnt4882_pci_driver); } #ifdef CONFIG_GPIB_PCMCIA #include #include #include #include #include #include #include #include #include static int ni_gpib_config(struct pcmcia_device *link); static void ni_gpib_release(struct pcmcia_device *link); static void ni_pcmcia_detach(struct gpib_board *board); /* * A linked list of "instances" of the dummy 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. * * I think this dev_list is obsolete but the pointer is needed to keep * the module instance for the ni_pcmcia_attach function. */ static struct pcmcia_device *curr_dev; struct local_info_t { struct pcmcia_device *p_dev; struct gpib_board *dev; int stop; struct bus_operations *bus; }; /* * ni_gpib_probe() creates an "instance" of the driver, allocating * local data structures for one device. The device is registered * with Card Services. */ static int ni_gpib_probe(struct pcmcia_device *link) { struct local_info_t *info; //struct struct gpib_board *dev; /* Allocate space for private device-specific data */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->p_dev = link; link->priv = info; /* * General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for almost * everything. In most clients, many details (i.e., number, sizes, * and attributes of IO windows) are fixed by the nature of the * device, and can be hard-wired here. */ link->config_flags = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; /* Register with Card Services */ curr_dev = link; return ni_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 ni_gpib_remove(struct pcmcia_device *link) { struct local_info_t *info = link->priv; //struct struct gpib_board *dev = info->dev; if (info->dev) ni_pcmcia_detach(info->dev); ni_gpib_release(link); //free_netdev(dev); kfree(info); } static int ni_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) { int retval; retval = pcmcia_request_io(link); if (retval != 0) return retval; return 0; } /* * ni_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 ni_gpib_config(struct pcmcia_device *link) { //struct local_info_t *info = link->priv; //struct gpib_board *dev = info->dev; int last_ret; last_ret = pcmcia_loop_config(link, &ni_gpib_config_iteration, NULL); if (last_ret) { dev_warn(&link->dev, "no configuration found\n"); ni_gpib_release(link); return last_ret; } last_ret = pcmcia_enable_device(link); if (last_ret) { ni_gpib_release(link); return last_ret; } return 0; } /* ni_gpib_config */ /* * After a card is removed, ni_gpib_release() will unregister the * device, and release the PCMCIA configuration. If the device is * still open, this will be postponed until it is closed. */ static void ni_gpib_release(struct pcmcia_device *link) { pcmcia_disable_device(link); } /* ni_gpib_release */ static int ni_gpib_suspend(struct pcmcia_device *link) { //struct local_info_t *info = link->priv; //struct struct gpib_board *dev = info->dev; if (link->open) dev_warn(&link->dev, "Device still open\n"); //netif_device_detach(dev); return 0; } static int ni_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 ni_gpib_config(link); } static struct pcmcia_device_id ni_pcmcia_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4882), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0c71), // NI PCMCIA-GPIB+ PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, ni_pcmcia_ids); static struct pcmcia_driver ni_gpib_cs_driver = { .name = "ni_gpib_cs", .owner = THIS_MODULE, .drv = { .name = "ni_gpib_cs", }, .id_table = ni_pcmcia_ids, .probe = ni_gpib_probe, .remove = ni_gpib_remove, .suspend = ni_gpib_suspend, .resume = ni_gpib_resume, }; static int __init init_ni_gpib_cs(void) { return pcmcia_register_driver(&ni_gpib_cs_driver); } static void __exit exit_ni_gpib_cs(void) { pcmcia_unregister_driver(&ni_gpib_cs_driver); } static const int pcmcia_gpib_iosize = 32; static int ni_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config) { struct local_info_t *info; struct tnt4882_priv *tnt_priv; struct nec7210_priv *nec_priv; int isr_flags = IRQF_SHARED; int retval; if (!curr_dev) return -ENODEV; info = curr_dev->priv; info->dev = board; board->status = 0; if (tnt4882_allocate_private(board)) return -ENOMEM; tnt_priv = board->private_data; nec_priv = &tnt_priv->nec7210_priv; nec_priv->type = TNT4882; nec_priv->read_byte = nec7210_locking_ioport_read_byte; nec_priv->write_byte = nec7210_locking_ioport_write_byte; nec_priv->offset = atgpib_reg_offset; if (!request_region(curr_dev->resource[0]->start, resource_size(curr_dev->resource[0]), DRV_NAME)) return -ENOMEM; nec_priv->mmiobase = ioport_map(curr_dev->resource[0]->start, resource_size(curr_dev->resource[0])); if (!nec_priv->mmiobase) return -ENOMEM; // get irq retval = request_irq(curr_dev->irq, tnt4882_interrupt, isr_flags, DRV_NAME, board); if (retval) { dev_err(board->gpib_dev, "failed to obtain PCMCIA irq %d\n", curr_dev->irq); return retval; } tnt_priv->irq = curr_dev->irq; tnt4882_init(tnt_priv, board); return 0; } static void ni_pcmcia_detach(struct gpib_board *board) { struct tnt4882_priv *tnt_priv = board->private_data; struct nec7210_priv *nec_priv; if (tnt_priv) { nec_priv = &tnt_priv->nec7210_priv; if (tnt_priv->irq) free_irq(tnt_priv->irq, board); if (nec_priv->mmiobase) ioport_unmap(nec_priv->mmiobase); if (nec_priv->iobase) { tnt4882_board_reset(tnt_priv, board); release_region(nec_priv->iobase, pcmcia_gpib_iosize); } } tnt4882_free_private(board); } static gpib_interface_t ni_pcmcia_interface = { .name = "ni_pcmcia", .attach = ni_pcmcia_attach, .detach = ni_pcmcia_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response = tnt4882_serial_poll_response, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; static gpib_interface_t ni_pcmcia_accel_interface = { .name = "ni_pcmcia_accel", .attach = ni_pcmcia_attach, .detach = ni_pcmcia_detach, .read = tnt4882_accel_read, .write = tnt4882_accel_write, .command = tnt4882_command, .take_control = tnt4882_take_control, .go_to_standby = tnt4882_go_to_standby, .request_system_control = tnt4882_request_system_control, .interface_clear = tnt4882_interface_clear, .remote_enable = tnt4882_remote_enable, .enable_eos = tnt4882_enable_eos, .disable_eos = tnt4882_disable_eos, .parallel_poll = tnt4882_parallel_poll, .parallel_poll_configure = tnt4882_parallel_poll_configure, .parallel_poll_response = tnt4882_parallel_poll_response, .local_parallel_poll_mode = NULL, // XXX .line_status = tnt4882_line_status, .update_status = tnt4882_update_status, .primary_address = tnt4882_primary_address, .secondary_address = tnt4882_secondary_address, .serial_poll_response = tnt4882_serial_poll_response, .serial_poll_status = tnt4882_serial_poll_status, .t1_delay = tnt4882_t1_delay, .return_to_local = tnt4882_return_to_local, }; #endif // CONFIG_GPIB_PCMCIA module_init(tnt4882_init_module); module_exit(tnt4882_exit_module);