| // SPDX-License-Identifier: GPL-2.0 |
| |
| /*************************************************************************** |
| * copyright : (C) 2001, 2002 by Frank Mori Hess |
| ***************************************************************************/ |
| |
| #define dev_fmt(fmt) KBUILD_MODNAME ": " fmt |
| |
| #include "board.h" |
| #include <linux/ioport.h> |
| #include <linux/sched.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <asm/dma.h> |
| #include <linux/bitops.h> |
| #include <linux/pci.h> |
| #include <linux/pci_ids.h> |
| #include <linux/string.h> |
| #include <linux/init.h> |
| #include <linux/spinlock.h> |
| #include <linux/delay.h> |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("GPIB library code for NEC uPD7210"); |
| |
| int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_byte, |
| int compare_8_bits) |
| { |
| write_byte(priv, eos_byte, EOSR); |
| priv->auxa_bits |= HR_REOS; |
| if (compare_8_bits) |
| priv->auxa_bits |= HR_BIN; |
| else |
| priv->auxa_bits &= ~HR_BIN; |
| write_byte(priv, priv->auxa_bits, AUXMR); |
| return 0; |
| } |
| EXPORT_SYMBOL(nec7210_enable_eos); |
| |
| void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| priv->auxa_bits &= ~HR_REOS; |
| write_byte(priv, priv->auxa_bits, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_disable_eos); |
| |
| int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result) |
| { |
| int ret; |
| |
| clear_bit(COMMAND_READY_BN, &priv->state); |
| |
| // execute parallel poll |
| write_byte(priv, AUX_EPP, AUXMR); |
| // wait for result FIXME: support timeouts |
| ret = wait_event_interruptible(board->wait, test_bit(COMMAND_READY_BN, &priv->state)); |
| if (ret) { |
| dev_dbg(board->gpib_dev, "gpib: parallel poll interrupted\n"); |
| return -ERESTARTSYS; |
| } |
| *result = read_byte(priv, CPTR); |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(nec7210_parallel_poll); |
| |
| void nec7210_parallel_poll_configure(struct gpib_board *board, |
| struct nec7210_priv *priv, unsigned int configuration) |
| { |
| write_byte(priv, PPR | configuration, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_parallel_poll_configure); |
| |
| void nec7210_parallel_poll_response(struct gpib_board *board, struct nec7210_priv *priv, int ist) |
| { |
| if (ist) |
| write_byte(priv, AUX_SPPF, AUXMR); |
| else |
| write_byte(priv, AUX_CPPF, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_parallel_poll_response); |
| /* |
| * This is really only adequate for chips that do a 488.2 style reqt/reqf |
| * based on bit 6 of the SPMR (see chapter 11.3.3 of 488.2). For simpler chips that simply |
| * set rsv directly based on bit 6, we either need to do more hardware setup to expose |
| * the 488.2 capability (for example with NI chips), or we need to implement the |
| * 488.2 set srv state machine in the driver (if that is even viable). |
| */ |
| void nec7210_serial_poll_response(struct gpib_board *board, |
| struct nec7210_priv *priv, u8 status) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| if (status & request_service_bit) { |
| priv->srq_pending = 1; |
| clear_bit(SPOLL_NUM, &board->status); |
| |
| } else { |
| priv->srq_pending = 0; |
| } |
| write_byte(priv, status, SPMR); |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| } |
| EXPORT_SYMBOL(nec7210_serial_poll_response); |
| |
| u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| return read_byte(priv, SPSR); |
| } |
| EXPORT_SYMBOL(nec7210_serial_poll_status); |
| |
| int nec7210_primary_address(const struct gpib_board *board, struct nec7210_priv *priv, |
| unsigned int address) |
| { |
| // put primary address in address0 |
| write_byte(priv, address & ADDRESS_MASK, ADR); |
| return 0; |
| } |
| EXPORT_SYMBOL(nec7210_primary_address); |
| |
| int nec7210_secondary_address(const struct gpib_board *board, struct nec7210_priv *priv, |
| unsigned int address, int enable) |
| { |
| if (enable) { |
| // put secondary address in address1 |
| write_byte(priv, HR_ARS | (address & ADDRESS_MASK), ADR); |
| // go to address mode 2 |
| priv->reg_bits[ADMR] &= ~HR_ADM0; |
| priv->reg_bits[ADMR] |= HR_ADM1; |
| } else { |
| // disable address1 register |
| write_byte(priv, HR_ARS | HR_DT | HR_DL, ADR); |
| // go to address mode 1 |
| priv->reg_bits[ADMR] |= HR_ADM0; |
| priv->reg_bits[ADMR] &= ~HR_ADM1; |
| } |
| write_byte(priv, priv->reg_bits[ADMR], ADMR); |
| return 0; |
| } |
| EXPORT_SYMBOL(nec7210_secondary_address); |
| |
| static void update_talker_state(struct nec7210_priv *priv, unsigned int address_status_bits) |
| { |
| if ((address_status_bits & HR_TA)) { |
| if ((address_status_bits & HR_NATN)) { |
| if (address_status_bits & HR_SPMS) |
| priv->talker_state = serial_poll_active; |
| else |
| priv->talker_state = talker_active; |
| } else { |
| priv->talker_state = talker_addressed; |
| } |
| } else { |
| priv->talker_state = talker_idle; |
| } |
| } |
| |
| static void update_listener_state(struct nec7210_priv *priv, unsigned int address_status_bits) |
| { |
| if (address_status_bits & HR_LA) { |
| if ((address_status_bits & HR_NATN)) |
| priv->listener_state = listener_active; |
| else |
| priv->listener_state = listener_addressed; |
| } else { |
| priv->listener_state = listener_idle; |
| } |
| } |
| |
| unsigned int nec7210_update_status_nolock(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| int address_status_bits; |
| u8 spoll_status; |
| |
| if (!priv) |
| return 0; |
| |
| address_status_bits = read_byte(priv, ADSR); |
| if (address_status_bits & HR_CIC) |
| set_bit(CIC_NUM, &board->status); |
| else |
| clear_bit(CIC_NUM, &board->status); |
| // check for talker/listener addressed |
| update_talker_state(priv, address_status_bits); |
| if (priv->talker_state == talker_active || priv->talker_state == talker_addressed) |
| set_bit(TACS_NUM, &board->status); |
| else |
| clear_bit(TACS_NUM, &board->status); |
| update_listener_state(priv, address_status_bits); |
| if (priv->listener_state == listener_active || |
| priv->listener_state == listener_addressed) |
| set_bit(LACS_NUM, &board->status); |
| else |
| clear_bit(LACS_NUM, &board->status); |
| if (address_status_bits & HR_NATN) |
| clear_bit(ATN_NUM, &board->status); |
| else |
| set_bit(ATN_NUM, &board->status); |
| spoll_status = nec7210_serial_poll_status(board, priv); |
| if (priv->srq_pending && (spoll_status & request_service_bit) == 0) { |
| priv->srq_pending = 0; |
| set_bit(SPOLL_NUM, &board->status); |
| } |
| |
| /* |
| * we rely on the interrupt handler to set the |
| * rest of the status bits |
| */ |
| |
| return board->status; |
| } |
| EXPORT_SYMBOL(nec7210_update_status_nolock); |
| |
| unsigned int nec7210_update_status(struct gpib_board *board, struct nec7210_priv *priv, |
| unsigned int clear_mask) |
| { |
| unsigned long flags; |
| unsigned int retval; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| board->status &= ~clear_mask; |
| retval = nec7210_update_status_nolock(board, priv); |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_update_status); |
| |
| unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg, |
| unsigned int mask, unsigned int bits) |
| { |
| priv->reg_bits[reg] &= ~mask; |
| priv->reg_bits[reg] |= mask & bits; |
| write_byte(priv, priv->reg_bits[reg], reg); |
| return priv->reg_bits[reg]; |
| } |
| EXPORT_SYMBOL(nec7210_set_reg_bits); |
| |
| void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *priv, int mode) |
| { |
| unsigned long flags; |
| |
| mode &= HR_HANDSHAKE_MASK; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| if ((priv->auxa_bits & HR_HANDSHAKE_MASK) != mode) { |
| priv->auxa_bits &= ~HR_HANDSHAKE_MASK; |
| priv->auxa_bits |= mode; |
| write_byte(priv, priv->auxa_bits, AUXMR); |
| } |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| } |
| EXPORT_SYMBOL(nec7210_set_handshake_mode); |
| |
| u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end) |
| { |
| unsigned long flags; |
| u8 data; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| data = read_byte(priv, DIR); |
| clear_bit(READ_READY_BN, &priv->state); |
| if (test_and_clear_bit(RECEIVED_END_BN, &priv->state)) |
| *end = 1; |
| else |
| *end = 0; |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| |
| return data; |
| } |
| EXPORT_SYMBOL(nec7210_read_data_in); |
| |
| int nec7210_take_control(struct gpib_board *board, struct nec7210_priv *priv, int syncronous) |
| { |
| int i; |
| const int timeout = 100; |
| int retval = 0; |
| unsigned int adsr_bits = 0; |
| |
| if (syncronous) |
| write_byte(priv, AUX_TCS, AUXMR); |
| else |
| write_byte(priv, AUX_TCA, AUXMR); |
| // busy wait until ATN is asserted |
| for (i = 0; i < timeout; i++) { |
| adsr_bits = read_byte(priv, ADSR); |
| if ((adsr_bits & HR_NATN) == 0) |
| break; |
| udelay(1); |
| } |
| if (i == timeout) |
| return -ETIMEDOUT; |
| |
| clear_bit(WRITE_READY_BN, &priv->state); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_take_control); |
| |
| int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| int i; |
| const int timeout = 1000; |
| unsigned int adsr_bits = 0; |
| int retval = 0; |
| |
| write_byte(priv, AUX_GTS, AUXMR); |
| // busy wait until ATN is released |
| for (i = 0; i < timeout; i++) { |
| adsr_bits = read_byte(priv, ADSR); |
| if (adsr_bits & HR_NATN) |
| break; |
| udelay(1); |
| } |
| // if busy wait has failed, try sleeping |
| if (i == timeout) { |
| for (i = 0; i < HZ; i++) { |
| set_current_state(TASK_INTERRUPTIBLE); |
| if (schedule_timeout(1)) |
| return -ERESTARTSYS; |
| adsr_bits = read_byte(priv, ADSR); |
| if (adsr_bits & HR_NATN) |
| break; |
| } |
| if (i == HZ) |
| return -ETIMEDOUT; |
| } |
| |
| clear_bit(COMMAND_READY_BN, &priv->state); |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_go_to_standby); |
| |
| int nec7210_request_system_control(struct gpib_board *board, struct nec7210_priv *priv, |
| int request_control) |
| { |
| if (request_control == 0) { |
| write_byte(priv, AUX_CREN, AUXMR); |
| write_byte(priv, AUX_CIFC, AUXMR); |
| write_byte(priv, AUX_DSC, AUXMR); |
| } |
| return 0; |
| } |
| EXPORT_SYMBOL(nec7210_request_system_control); |
| |
| void nec7210_interface_clear(struct gpib_board *board, struct nec7210_priv *priv, int assert) |
| { |
| if (assert) |
| write_byte(priv, AUX_SIFC, AUXMR); |
| else |
| write_byte(priv, AUX_CIFC, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_interface_clear); |
| |
| void nec7210_remote_enable(struct gpib_board *board, struct nec7210_priv *priv, int enable) |
| { |
| if (enable) |
| write_byte(priv, AUX_SREN, AUXMR); |
| else |
| write_byte(priv, AUX_CREN, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_remote_enable); |
| |
| void nec7210_release_rfd_holdoff(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| if (test_bit(RFD_HOLDOFF_BN, &priv->state) && |
| test_bit(READ_READY_BN, &priv->state) == 0) { |
| write_byte(priv, AUX_FH, AUXMR); |
| clear_bit(RFD_HOLDOFF_BN, &priv->state); |
| } |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| } |
| EXPORT_SYMBOL(nec7210_release_rfd_holdoff); |
| |
| int nec7210_t1_delay(struct gpib_board *board, struct nec7210_priv *priv, |
| unsigned int nano_sec) |
| { |
| unsigned int retval; |
| |
| if (nano_sec <= 500) { |
| priv->auxb_bits |= HR_TRI; |
| retval = 500; |
| } else { |
| priv->auxb_bits &= ~HR_TRI; |
| retval = 2000; |
| } |
| write_byte(priv, priv->auxb_bits, AUXMR); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_t1_delay); |
| |
| void nec7210_return_to_local(const struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| write_byte(priv, AUX_RTL, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_return_to_local); |
| |
| static inline short nec7210_atn_has_changed(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| short address_status_bits = read_byte(priv, ADSR); |
| |
| if (address_status_bits & HR_NATN) { |
| if (test_bit(ATN_NUM, &board->status)) |
| return 1; |
| else |
| return 0; |
| } else { |
| if (test_bit(ATN_NUM, &board->status)) |
| return 0; |
| else |
| return 1; |
| } |
| return -1; |
| } |
| |
| int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8 |
| *buffer, size_t length, size_t *bytes_written) |
| { |
| int retval = 0; |
| unsigned long flags; |
| |
| *bytes_written = 0; |
| |
| clear_bit(BUS_ERROR_BN, &priv->state); |
| |
| while (*bytes_written < length) { |
| if (wait_event_interruptible(board->wait, |
| test_bit(COMMAND_READY_BN, &priv->state) || |
| test_bit(BUS_ERROR_BN, &priv->state) || |
| test_bit(TIMO_NUM, &board->status))) { |
| dev_dbg(board->gpib_dev, "command wait interrupted\n"); |
| retval = -ERESTARTSYS; |
| break; |
| } |
| if (test_bit(TIMO_NUM, &board->status)) |
| break; |
| if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) |
| break; |
| spin_lock_irqsave(&board->spinlock, flags); |
| clear_bit(COMMAND_READY_BN, &priv->state); |
| write_byte(priv, buffer[*bytes_written], CDOR); |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| |
| ++(*bytes_written); |
| |
| if (need_resched()) |
| schedule(); |
| } |
| // wait for last byte to get sent |
| if (wait_event_interruptible(board->wait, test_bit(COMMAND_READY_BN, &priv->state) || |
| test_bit(BUS_ERROR_BN, &priv->state) || |
| test_bit(TIMO_NUM, &board->status))) |
| retval = -ERESTARTSYS; |
| |
| if (test_bit(TIMO_NUM, &board->status)) |
| retval = -ETIMEDOUT; |
| |
| if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) |
| retval = -EIO; |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_command); |
| |
| static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, |
| size_t length, int *end, size_t *bytes_read) |
| { |
| ssize_t retval = 0; |
| |
| *bytes_read = 0; |
| *end = 0; |
| |
| while (*bytes_read < length) { |
| if (wait_event_interruptible(board->wait, |
| test_bit(READ_READY_BN, &priv->state) || |
| test_bit(DEV_CLEAR_BN, &priv->state) || |
| test_bit(TIMO_NUM, &board->status))) { |
| retval = -ERESTARTSYS; |
| break; |
| } |
| if (test_bit(READ_READY_BN, &priv->state)) { |
| if (*bytes_read == 0) { |
| /* |
| * We set the handshake mode here because we know |
| * no new bytes will arrive (it has already arrived |
| * and is awaiting being read out of the chip) while we are changing |
| * modes. This ensures we can reliably keep track |
| * of the holdoff state. |
| */ |
| nec7210_set_handshake_mode(board, priv, HR_HLDA); |
| } |
| buffer[(*bytes_read)++] = nec7210_read_data_in(board, priv, end); |
| if (*end) |
| break; |
| } |
| if (test_bit(TIMO_NUM, &board->status)) { |
| retval = -ETIMEDOUT; |
| break; |
| } |
| if (test_bit(DEV_CLEAR_BN, &priv->state)) { |
| retval = -EINTR; |
| break; |
| } |
| |
| if (*bytes_read < length) |
| nec7210_release_rfd_holdoff(board, priv); |
| |
| if (need_resched()) |
| schedule(); |
| } |
| return retval; |
| } |
| |
| #ifdef NEC_DMA |
| static ssize_t __dma_read(struct gpib_board *board, struct nec7210_priv *priv, size_t length) |
| { |
| ssize_t retval = 0; |
| size_t count = 0; |
| unsigned long flags, dma_irq_flags; |
| |
| if (length == 0) |
| return 0; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| |
| dma_irq_flags = claim_dma_lock(); |
| disable_dma(priv->dma_channel); |
| /* program dma controller */ |
| clear_dma_ff(priv->dma_channel); |
| set_dma_count(priv->dma_channel, length); |
| set_dma_addr(priv->dma_channel, priv->dma_buffer_addr); |
| set_dma_mode(priv->dma_channel, DMA_MODE_READ); |
| release_dma_lock(dma_irq_flags); |
| |
| enable_dma(priv->dma_channel); |
| |
| set_bit(DMA_READ_IN_PROGRESS_BN, &priv->state); |
| clear_bit(READ_READY_BN, &priv->state); |
| |
| // enable nec7210 dma |
| nec7210_set_reg_bits(priv, IMR2, HR_DMAI, HR_DMAI); |
| |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| |
| // wait for data to transfer |
| if (wait_event_interruptible(board->wait, |
| test_bit(DMA_READ_IN_PROGRESS_BN, &priv->state) == 0 || |
| test_bit(DEV_CLEAR_BN, &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, &priv->state)) |
| retval = -EINTR; |
| |
| // disable nec7210 dma |
| nec7210_set_reg_bits(priv, IMR2, HR_DMAI, 0); |
| |
| // record how many bytes we transferred |
| flags = claim_dma_lock(); |
| clear_dma_ff(priv->dma_channel); |
| disable_dma(priv->dma_channel); |
| count += length - get_dma_residue(priv->dma_channel); |
| release_dma_lock(flags); |
| |
| return retval ? retval : count; |
| } |
| |
| static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, |
| size_t length) |
| { |
| size_t remain = length; |
| size_t transfer_size; |
| ssize_t retval = 0; |
| |
| while (remain > 0) { |
| transfer_size = (priv->dma_buffer_length < remain) ? |
| priv->dma_buffer_length : remain; |
| retval = __dma_read(board, priv, transfer_size); |
| if (retval < 0) |
| break; |
| memcpy(buffer, priv->dma_buffer, transfer_size); |
| remain -= retval; |
| buffer += retval; |
| if (test_bit(RECEIVED_END_BN, &priv->state)) |
| break; |
| } |
| |
| if (retval < 0) |
| return retval; |
| |
| return length - remain; |
| } |
| #endif |
| |
| int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, |
| size_t length, int *end, size_t *bytes_read) |
| { |
| ssize_t retval = 0; |
| |
| *end = 0; |
| *bytes_read = 0; |
| |
| if (length == 0) |
| return 0; |
| |
| clear_bit(DEV_CLEAR_BN, &priv->state); // XXX wrong |
| |
| nec7210_release_rfd_holdoff(board, priv); |
| |
| retval = pio_read(board, priv, buffer, length, end, bytes_read); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_read); |
| |
| static int pio_write_wait(struct gpib_board *board, struct nec7210_priv *priv, |
| short wake_on_lacs, short wake_on_atn, short wake_on_bus_error) |
| { |
| // wait until byte is ready to be sent |
| if (wait_event_interruptible(board->wait, |
| (test_bit(TACS_NUM, &board->status) && |
| test_bit(WRITE_READY_BN, &priv->state)) || |
| test_bit(DEV_CLEAR_BN, &priv->state) || |
| (wake_on_bus_error && test_bit(BUS_ERROR_BN, &priv->state)) || |
| (wake_on_lacs && test_bit(LACS_NUM, &board->status)) || |
| (wake_on_atn && test_bit(ATN_NUM, &board->status)) || |
| test_bit(TIMO_NUM, &board->status))) |
| return -ERESTARTSYS; |
| |
| if (test_bit(TIMO_NUM, &board->status)) |
| return -ETIMEDOUT; |
| |
| if (test_bit(DEV_CLEAR_BN, &priv->state)) |
| return -EINTR; |
| |
| if (wake_on_bus_error && test_and_clear_bit(BUS_ERROR_BN, &priv->state)) |
| return -EIO; |
| |
| return 0; |
| } |
| |
| static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, |
| size_t length, size_t *bytes_written) |
| { |
| size_t last_count = 0; |
| ssize_t retval = 0; |
| unsigned long flags; |
| const int max_bus_errors = (length > 1000) ? length : 1000; |
| int bus_error_count = 0; |
| *bytes_written = 0; |
| |
| clear_bit(BUS_ERROR_BN, &priv->state); |
| |
| while (*bytes_written < length) { |
| if (need_resched()) |
| schedule(); |
| |
| retval = pio_write_wait(board, priv, 0, 0, priv->type == NEC7210); |
| if (retval == -EIO) { |
| /* resend last byte on bus error */ |
| *bytes_written = last_count; |
| /* |
| * we can get unrecoverable bus errors, |
| * so give up after a while |
| */ |
| bus_error_count++; |
| if (bus_error_count > max_bus_errors) |
| return retval; |
| continue; |
| } else { |
| if (retval < 0) |
| return retval; |
| } |
| spin_lock_irqsave(&board->spinlock, flags); |
| clear_bit(BUS_ERROR_BN, &priv->state); |
| clear_bit(WRITE_READY_BN, &priv->state); |
| last_count = *bytes_written; |
| write_byte(priv, buffer[(*bytes_written)++], CDOR); |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| } |
| retval = pio_write_wait(board, priv, 1, 1, priv->type == NEC7210); |
| return retval; |
| } |
| |
| #ifdef NEC_DMA |
| static ssize_t __dma_write(struct gpib_board *board, struct nec7210_priv *priv, dma_addr_t address, |
| size_t length) |
| { |
| unsigned long flags, dma_irq_flags; |
| int residue = 0; |
| int retval = 0; |
| |
| spin_lock_irqsave(&board->spinlock, flags); |
| |
| /* program dma controller */ |
| dma_irq_flags = claim_dma_lock(); |
| disable_dma(priv->dma_channel); |
| clear_dma_ff(priv->dma_channel); |
| set_dma_count(priv->dma_channel, length); |
| set_dma_addr(priv->dma_channel, address); |
| set_dma_mode(priv->dma_channel, DMA_MODE_WRITE); |
| enable_dma(priv->dma_channel); |
| release_dma_lock(dma_irq_flags); |
| |
| // enable board's dma for output |
| nec7210_set_reg_bits(priv, IMR2, HR_DMAO, HR_DMAO); |
| |
| clear_bit(WRITE_READY_BN, &priv->state); |
| set_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state); |
| |
| spin_unlock_irqrestore(&board->spinlock, flags); |
| |
| // suspend until message is sent |
| if (wait_event_interruptible(board->wait, |
| test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state) == 0 || |
| test_bit(BUS_ERROR_BN, &priv->state) || |
| test_bit(DEV_CLEAR_BN, &priv->state) || |
| test_bit(TIMO_NUM, &board->status))) |
| retval = -ERESTARTSYS; |
| |
| if (test_bit(TIMO_NUM, &board->status)) |
| retval = -ETIMEDOUT; |
| if (test_and_clear_bit(DEV_CLEAR_BN, &priv->state)) |
| retval = -EINTR; |
| if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) |
| retval = -EIO; |
| |
| // disable board's dma |
| nec7210_set_reg_bits(priv, IMR2, HR_DMAO, 0); |
| |
| dma_irq_flags = claim_dma_lock(); |
| clear_dma_ff(priv->dma_channel); |
| disable_dma(priv->dma_channel); |
| residue = get_dma_residue(priv->dma_channel); |
| release_dma_lock(dma_irq_flags); |
| |
| if (residue) |
| retval = -EPIPE; |
| |
| return retval ? retval : length; |
| } |
| |
| static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer, |
| size_t length) |
| { |
| size_t remain = length; |
| size_t transfer_size; |
| ssize_t retval = 0; |
| |
| while (remain > 0) { |
| transfer_size = (priv->dma_buffer_length < remain) ? |
| priv->dma_buffer_length : remain; |
| memcpy(priv->dma_buffer, buffer, transfer_size); |
| retval = __dma_write(board, priv, priv->dma_buffer_addr, transfer_size); |
| if (retval < 0) |
| break; |
| remain -= retval; |
| buffer += retval; |
| } |
| |
| if (retval < 0) |
| return retval; |
| |
| return length - remain; |
| } |
| #endif |
| int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, |
| u8 *buffer, size_t length, int send_eoi, |
| size_t *bytes_written) |
| { |
| int retval = 0; |
| |
| *bytes_written = 0; |
| |
| clear_bit(DEV_CLEAR_BN, &priv->state); // XXX |
| |
| if (send_eoi) |
| length-- ; // save the last byte for sending EOI |
| |
| if (length > 0) { |
| // isa dma transfer |
| if (0 /*priv->dma_channel*/) { |
| /* |
| * dma writes are unreliable since they can't recover from bus errors |
| * (which happen when ATN is asserted in the middle of a write) |
| */ |
| #ifdef NEC_DMA |
| retval = dma_write(board, priv, buffer, length); |
| if (retval < 0) |
| return retval; |
| count += retval; |
| #endif |
| } else { // PIO transfer |
| size_t num_bytes; |
| |
| retval = pio_write(board, priv, buffer, length, &num_bytes); |
| |
| *bytes_written += num_bytes; |
| if (retval < 0) |
| return retval; |
| } |
| } |
| if (send_eoi) { |
| size_t num_bytes; |
| |
| /* |
| * We need to wait to make sure we will immediately be able to write the data byte |
| * into the chip before sending the associated AUX_SEOI command. This is really |
| * only needed for length==1 since otherwise the earlier calls to pio_write |
| * will have dont the wait already. |
| */ |
| retval = pio_write_wait(board, priv, 0, 0, priv->type == NEC7210); |
| if (retval < 0) |
| return retval; |
| /*send EOI */ |
| write_byte(priv, AUX_SEOI, AUXMR); |
| |
| retval = pio_write(board, priv, &buffer[*bytes_written], 1, &num_bytes); |
| *bytes_written += num_bytes; |
| if (retval < 0) |
| return retval; |
| } |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_write); |
| |
| /* |
| * interrupt service routine |
| */ |
| irqreturn_t nec7210_interrupt(struct gpib_board *board, struct nec7210_priv *priv) |
| { |
| int status1, status2; |
| |
| // read interrupt status (also clears status) |
| status1 = read_byte(priv, ISR1); |
| status2 = read_byte(priv, ISR2); |
| |
| return nec7210_interrupt_have_status(board, priv, status1, status2); |
| } |
| EXPORT_SYMBOL(nec7210_interrupt); |
| |
| irqreturn_t nec7210_interrupt_have_status(struct gpib_board *board, |
| struct nec7210_priv *priv, int status1, int status2) |
| { |
| #ifdef NEC_DMA |
| unsigned long dma_flags; |
| #endif |
| int retval = IRQ_NONE; |
| |
| // record service request in status |
| if (status2 & HR_SRQI) |
| set_bit(SRQI_NUM, &board->status); |
| |
| // change in lockout status |
| if (status2 & HR_LOKC) { |
| if (status2 & HR_LOK) |
| set_bit(LOK_NUM, &board->status); |
| else |
| clear_bit(LOK_NUM, &board->status); |
| } |
| |
| // change in remote status |
| if (status2 & HR_REMC) { |
| if (status2 & HR_REM) |
| set_bit(REM_NUM, &board->status); |
| else |
| clear_bit(REM_NUM, &board->status); |
| } |
| |
| // record reception of END |
| if (status1 & HR_END) { |
| set_bit(RECEIVED_END_BN, &priv->state); |
| if ((priv->auxa_bits & HR_HANDSHAKE_MASK) == HR_HLDE) |
| set_bit(RFD_HOLDOFF_BN, &priv->state); |
| } |
| |
| // get incoming data in PIO mode |
| if ((status1 & HR_DI)) { |
| set_bit(READ_READY_BN, &priv->state); |
| if ((priv->auxa_bits & HR_HANDSHAKE_MASK) == HR_HLDA) |
| set_bit(RFD_HOLDOFF_BN, &priv->state); |
| } |
| #ifdef NEC_DMA |
| // check for dma read transfer complete |
| if (test_bit(DMA_READ_IN_PROGRESS_BN, &priv->state)) { |
| dma_flags = claim_dma_lock(); |
| disable_dma(priv->dma_channel); |
| clear_dma_ff(priv->dma_channel); |
| if ((status1 & HR_END) || get_dma_residue(priv->dma_channel) == 0) |
| clear_bit(DMA_READ_IN_PROGRESS_BN, &priv->state); |
| else |
| enable_dma(priv->dma_channel); |
| release_dma_lock(dma_flags); |
| } |
| #endif |
| if ((status1 & HR_DO)) { |
| if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state) == 0) |
| set_bit(WRITE_READY_BN, &priv->state); |
| #ifdef NEC_DMA |
| if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state)) { // write data, isa dma mode |
| // check if dma transfer is complete |
| dma_flags = claim_dma_lock(); |
| disable_dma(priv->dma_channel); |
| clear_dma_ff(priv->dma_channel); |
| if (get_dma_residue(priv->dma_channel) == 0) { |
| clear_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state); |
| // XXX race? byte may still be in CDOR reg |
| } else { |
| clear_bit(WRITE_READY_BN, &priv->state); |
| enable_dma(priv->dma_channel); |
| } |
| release_dma_lock(dma_flags); |
| } |
| #endif |
| } |
| |
| // outgoing command can be sent |
| if (status2 & HR_CO) |
| set_bit(COMMAND_READY_BN, &priv->state); |
| |
| // command pass through received |
| if (status1 & HR_CPT) |
| write_byte(priv, AUX_NVAL, AUXMR); |
| |
| if (status1 & HR_ERR) |
| set_bit(BUS_ERROR_BN, &priv->state); |
| |
| if (status1 & HR_DEC) { |
| unsigned short address_status_bits = read_byte(priv, ADSR); |
| |
| // ignore device clear events if we are controller in charge |
| if ((address_status_bits & HR_CIC) == 0) { |
| push_gpib_event(board, EVENT_DEV_CLR); |
| set_bit(DEV_CLEAR_BN, &priv->state); |
| } |
| } |
| |
| if (status1 & HR_DET) |
| push_gpib_event(board, EVENT_DEV_TRG); |
| |
| // Addressing status has changed |
| if (status2 & HR_ADSC) |
| set_bit(ADR_CHANGE_BN, &priv->state); |
| |
| if ((status1 & priv->reg_bits[IMR1]) || |
| (status2 & (priv->reg_bits[IMR2] & IMR2_ENABLE_INTR_MASK)) || |
| nec7210_atn_has_changed(board, priv)) { |
| nec7210_update_status_nolock(board, priv); |
| dev_dbg(board->gpib_dev, "minor %i, stat %lx, isr1 0x%x, imr1 0x%x, isr2 0x%x, imr2 0x%x\n", |
| board->minor, board->status, status1, priv->reg_bits[IMR1], status2, |
| priv->reg_bits[IMR2]); |
| wake_up_interruptible(&board->wait); /* wake up sleeping process */ |
| retval = IRQ_HANDLED; |
| } |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_interrupt_have_status); |
| |
| void nec7210_board_reset(struct nec7210_priv *priv, const struct gpib_board *board) |
| { |
| /* 7210 chip reset */ |
| write_byte(priv, AUX_CR, AUXMR); |
| |
| /* disable all interrupts */ |
| priv->reg_bits[IMR1] = 0; |
| write_byte(priv, priv->reg_bits[IMR1], IMR1); |
| priv->reg_bits[IMR2] = 0; |
| write_byte(priv, priv->reg_bits[IMR2], IMR2); |
| write_byte(priv, 0, SPMR); |
| |
| /* clear registers by reading */ |
| read_byte(priv, CPTR); |
| read_byte(priv, ISR1); |
| read_byte(priv, ISR2); |
| |
| /* parallel poll unconfigure */ |
| write_byte(priv, PPR | HR_PPU, AUXMR); |
| |
| priv->reg_bits[ADMR] = HR_TRM0 | HR_TRM1; |
| |
| priv->auxa_bits = AUXRA | HR_HLDA; |
| write_byte(priv, priv->auxa_bits, AUXMR); |
| |
| write_byte(priv, AUXRE | 0, AUXMR); |
| |
| /* set INT pin to active high, enable command pass through of unknown commands */ |
| priv->auxb_bits = AUXRB | HR_CPTE; |
| write_byte(priv, priv->auxb_bits, AUXMR); |
| write_byte(priv, AUXRE, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_board_reset); |
| |
| void nec7210_board_online(struct nec7210_priv *priv, const struct gpib_board *board) |
| { |
| /* set GPIB address */ |
| nec7210_primary_address(board, priv, board->pad); |
| nec7210_secondary_address(board, priv, board->sad, board->sad >= 0); |
| |
| /* enable interrupts */ |
| priv->reg_bits[IMR1] = HR_ERRIE | HR_DECIE | HR_ENDIE | |
| HR_DETIE | HR_CPTIE | HR_DOIE | HR_DIIE; |
| priv->reg_bits[IMR2] = IMR2_ENABLE_INTR_MASK; |
| write_byte(priv, priv->reg_bits[IMR1], IMR1); |
| write_byte(priv, priv->reg_bits[IMR2], IMR2); |
| |
| write_byte(priv, AUX_PON, AUXMR); |
| } |
| EXPORT_SYMBOL(nec7210_board_online); |
| |
| #ifdef CONFIG_HAS_IOPORT |
| /* wrappers for io */ |
| u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) |
| { |
| return inb(priv->iobase + register_num * priv->offset); |
| } |
| EXPORT_SYMBOL(nec7210_ioport_read_byte); |
| |
| void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) |
| { |
| if (register_num == AUXMR) |
| /* |
| * locking makes absolutely sure noone accesses the |
| * AUXMR register faster than once per microsecond |
| */ |
| nec7210_locking_ioport_write_byte(priv, data, register_num); |
| else |
| outb(data, priv->iobase + register_num * priv->offset); |
| } |
| EXPORT_SYMBOL(nec7210_ioport_write_byte); |
| |
| /* locking variants of io wrappers, for chips that page-in registers */ |
| u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) |
| { |
| u8 retval; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->register_page_lock, flags); |
| retval = inb(priv->iobase + register_num * priv->offset); |
| spin_unlock_irqrestore(&priv->register_page_lock, flags); |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_locking_ioport_read_byte); |
| |
| void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data, |
| unsigned int register_num) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->register_page_lock, flags); |
| if (register_num == AUXMR) |
| udelay(1); |
| outb(data, priv->iobase + register_num * priv->offset); |
| spin_unlock_irqrestore(&priv->register_page_lock, flags); |
| } |
| EXPORT_SYMBOL(nec7210_locking_ioport_write_byte); |
| #endif |
| |
| u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) |
| { |
| return readb(priv->mmiobase + register_num * priv->offset); |
| } |
| EXPORT_SYMBOL(nec7210_iomem_read_byte); |
| |
| void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num) |
| { |
| if (register_num == AUXMR) |
| /* |
| * locking makes absolutely sure noone accesses the |
| * AUXMR register faster than once per microsecond |
| */ |
| nec7210_locking_iomem_write_byte(priv, data, register_num); |
| else |
| writeb(data, priv->mmiobase + register_num * priv->offset); |
| } |
| EXPORT_SYMBOL(nec7210_iomem_write_byte); |
| |
| u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) |
| { |
| u8 retval; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->register_page_lock, flags); |
| retval = readb(priv->mmiobase + register_num * priv->offset); |
| spin_unlock_irqrestore(&priv->register_page_lock, flags); |
| return retval; |
| } |
| EXPORT_SYMBOL(nec7210_locking_iomem_read_byte); |
| |
| void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data, |
| unsigned int register_num) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->register_page_lock, flags); |
| if (register_num == AUXMR) |
| udelay(1); |
| writeb(data, priv->mmiobase + register_num * priv->offset); |
| spin_unlock_irqrestore(&priv->register_page_lock, flags); |
| } |
| EXPORT_SYMBOL(nec7210_locking_iomem_write_byte); |
| |
| static int __init nec7210_init_module(void) |
| { |
| return 0; |
| } |
| |
| static void __exit nec7210_exit_module(void) |
| { |
| } |
| |
| module_init(nec7210_init_module); |
| module_exit(nec7210_exit_module); |