diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/gsc_hpdi.c')
-rw-r--r-- | drivers/staging/comedi/drivers/gsc_hpdi.c | 723 |
1 files changed, 0 insertions, 723 deletions
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c deleted file mode 100644 index e35e4a743714..000000000000 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ /dev/null @@ -1,723 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * gsc_hpdi.c - * Comedi driver the General Standards Corporation - * High Speed Parallel Digital Interface rs485 boards. - * - * Author: Frank Mori Hess <fmhess@users.sourceforge.net> - * Copyright (C) 2003 Coherent Imaging Systems - * - * COMEDI - Linux Control and Measurement Device Interface - * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> - */ - -/* - * Driver: gsc_hpdi - * Description: General Standards Corporation High - * Speed Parallel Digital Interface rs485 boards - * Author: Frank Mori Hess <fmhess@users.sourceforge.net> - * Status: only receive mode works, transmit not supported - * Updated: Thu, 01 Nov 2012 16:17:38 +0000 - * Devices: [General Standards Corporation] PCI-HPDI32 (gsc_hpdi), - * PMC-HPDI32 - * - * Configuration options: - * None. - * - * Manual configuration of supported devices is not supported; they are - * configured automatically. - * - * There are some additional hpdi models available from GSC for which - * support could be added to this driver. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/interrupt.h> - -#include "../comedi_pci.h" - -#include "plx9080.h" - -/* - * PCI BAR2 Register map (dev->mmio) - */ -#define FIRMWARE_REV_REG 0x00 -#define FEATURES_REG_PRESENT_BIT BIT(15) -#define BOARD_CONTROL_REG 0x04 -#define BOARD_RESET_BIT BIT(0) -#define TX_FIFO_RESET_BIT BIT(1) -#define RX_FIFO_RESET_BIT BIT(2) -#define TX_ENABLE_BIT BIT(4) -#define RX_ENABLE_BIT BIT(5) -#define DEMAND_DMA_DIRECTION_TX_BIT BIT(6) /* ch 0 only */ -#define LINE_VALID_ON_STATUS_VALID_BIT BIT(7) -#define START_TX_BIT BIT(8) -#define CABLE_THROTTLE_ENABLE_BIT BIT(9) -#define TEST_MODE_ENABLE_BIT BIT(31) -#define BOARD_STATUS_REG 0x08 -#define COMMAND_LINE_STATUS_MASK (0x7f << 0) -#define TX_IN_PROGRESS_BIT BIT(7) -#define TX_NOT_EMPTY_BIT BIT(8) -#define TX_NOT_ALMOST_EMPTY_BIT BIT(9) -#define TX_NOT_ALMOST_FULL_BIT BIT(10) -#define TX_NOT_FULL_BIT BIT(11) -#define RX_NOT_EMPTY_BIT BIT(12) -#define RX_NOT_ALMOST_EMPTY_BIT BIT(13) -#define RX_NOT_ALMOST_FULL_BIT BIT(14) -#define RX_NOT_FULL_BIT BIT(15) -#define BOARD_JUMPER0_INSTALLED_BIT BIT(16) -#define BOARD_JUMPER1_INSTALLED_BIT BIT(17) -#define TX_OVERRUN_BIT BIT(21) -#define RX_UNDERRUN_BIT BIT(22) -#define RX_OVERRUN_BIT BIT(23) -#define TX_PROG_ALMOST_REG 0x0c -#define RX_PROG_ALMOST_REG 0x10 -#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) -#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) -#define FEATURES_REG 0x14 -#define FIFO_SIZE_PRESENT_BIT BIT(0) -#define FIFO_WORDS_PRESENT_BIT BIT(1) -#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT BIT(2) -#define GPIO_SUPPORTED_BIT BIT(3) -#define PLX_DMA_CH1_SUPPORTED_BIT BIT(4) -#define OVERRUN_UNDERRUN_SUPPORTED_BIT BIT(5) -#define FIFO_REG 0x18 -#define TX_STATUS_COUNT_REG 0x1c -#define TX_LINE_VALID_COUNT_REG 0x20, -#define TX_LINE_INVALID_COUNT_REG 0x24 -#define RX_STATUS_COUNT_REG 0x28 -#define RX_LINE_COUNT_REG 0x2c -#define INTERRUPT_CONTROL_REG 0x30 -#define FRAME_VALID_START_INTR BIT(0) -#define FRAME_VALID_END_INTR BIT(1) -#define TX_FIFO_EMPTY_INTR BIT(8) -#define TX_FIFO_ALMOST_EMPTY_INTR BIT(9) -#define TX_FIFO_ALMOST_FULL_INTR BIT(10) -#define TX_FIFO_FULL_INTR BIT(11) -#define RX_EMPTY_INTR BIT(12) -#define RX_ALMOST_EMPTY_INTR BIT(13) -#define RX_ALMOST_FULL_INTR BIT(14) -#define RX_FULL_INTR BIT(15) -#define INTERRUPT_STATUS_REG 0x34 -#define TX_CLOCK_DIVIDER_REG 0x38 -#define TX_FIFO_SIZE_REG 0x40 -#define RX_FIFO_SIZE_REG 0x44 -#define FIFO_SIZE_MASK (0xfffff << 0) -#define TX_FIFO_WORDS_REG 0x48 -#define RX_FIFO_WORDS_REG 0x4c -#define INTERRUPT_EDGE_LEVEL_REG 0x50 -#define INTERRUPT_POLARITY_REG 0x54 - -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -struct hpdi_private { - void __iomem *plx9080_mmio; - u32 *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ - /* physical addresses of dma buffers */ - dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; - /* - * array of dma descriptors read by plx9080, allocated to get proper - * alignment - */ - struct plx_dma_desc *dma_desc; - /* physical address of dma descriptor array */ - dma_addr_t dma_desc_phys_addr; - unsigned int num_dma_descriptors; - /* pointer to start of buffers indexed by descriptor */ - u32 *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; - /* index of the dma descriptor that is currently being used */ - unsigned int dma_desc_index; - unsigned int tx_fifo_size; - unsigned int rx_fifo_size; - unsigned long dio_count; - /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - unsigned int block_size; -}; - -static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_cmd *cmd = &s->async->cmd; - unsigned int idx; - unsigned int start; - unsigned int desc; - unsigned int size; - unsigned int next; - - next = readl(devpriv->plx9080_mmio + PLX_REG_DMAPADR(channel)); - - idx = devpriv->dma_desc_index; - start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); - /* loop until we have read all the full buffers */ - for (desc = 0; (next < start || next >= start + devpriv->block_size) && - desc < devpriv->num_dma_descriptors; desc++) { - /* transfer data from dma buffer to comedi buffer */ - size = devpriv->block_size / sizeof(u32); - if (cmd->stop_src == TRIG_COUNT) { - if (size > devpriv->dio_count) - size = devpriv->dio_count; - devpriv->dio_count -= size; - } - comedi_buf_write_samples(s, devpriv->desc_dio_buffer[idx], - size); - idx++; - idx %= devpriv->num_dma_descriptors; - start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); - - devpriv->dma_desc_index = idx; - } - /* XXX check for buffer overrun somehow */ -} - -static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - u32 hpdi_intr_status, hpdi_board_status; - u32 plx_status; - u32 plx_bits; - u8 dma0_status, dma1_status; - unsigned long flags; - - if (!dev->attached) - return IRQ_NONE; - - plx_status = readl(devpriv->plx9080_mmio + PLX_REG_INTCSR); - if ((plx_status & - (PLX_INTCSR_DMA0IA | PLX_INTCSR_DMA1IA | PLX_INTCSR_PLIA)) == 0) - return IRQ_NONE; - - hpdi_intr_status = readl(dev->mmio + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(dev->mmio + BOARD_STATUS_REG); - - if (hpdi_intr_status) - writel(hpdi_intr_status, dev->mmio + INTERRUPT_STATUS_REG); - - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR0); - if (plx_status & PLX_INTCSR_DMA0IA) { - /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, - devpriv->plx9080_mmio + PLX_REG_DMACSR0); - - if (dma0_status & PLX_DMACSR_ENABLE) - gsc_hpdi_drain_dma(dev, 0); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR1); - if (plx_status & PLX_INTCSR_DMA1IA) { - /* XXX */ /* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, - devpriv->plx9080_mmio + PLX_REG_DMACSR1); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* clear possible plx9080 interrupt sources */ - if (plx_status & PLX_INTCSR_LDBIA) { - /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_mmio + PLX_REG_L2PDBELL); - writel(plx_bits, devpriv->plx9080_mmio + PLX_REG_L2PDBELL); - } - - if (hpdi_board_status & RX_OVERRUN_BIT) { - dev_err(dev->class_dev, "rx fifo overrun\n"); - async->events |= COMEDI_CB_ERROR; - } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - dev_err(dev->class_dev, "rx fifo underrun\n"); - async->events |= COMEDI_CB_ERROR; - } - - if (devpriv->dio_count == 0) - async->events |= COMEDI_CB_EOA; - - comedi_handle_events(dev, s); - - return IRQ_HANDLED; -} - -static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(devpriv->plx9080_mmio, channel); - - spin_unlock_irqrestore(&dev->spinlock, flags); -} - -static int gsc_hpdi_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - writel(0, dev->mmio + BOARD_CONTROL_REG); - writel(0, dev->mmio + INTERRUPT_CONTROL_REG); - - gsc_hpdi_abort_dma(dev, 0); - - return 0; -} - -static int gsc_hpdi_cmd(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - unsigned long flags; - u32 bits; - - if (s->io_bits) - return -EINVAL; - - writel(RX_FIFO_RESET_BIT, dev->mmio + BOARD_CONTROL_REG); - - gsc_hpdi_abort_dma(dev, 0); - - devpriv->dma_desc_index = 0; - - /* - * These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. - */ - writel(0, devpriv->plx9080_mmio + PLX_REG_DMASIZ0); - writel(0, devpriv->plx9080_mmio + PLX_REG_DMAPADR0); - writel(0, devpriv->plx9080_mmio + PLX_REG_DMALADR0); - - /* give location of first dma descriptor */ - bits = devpriv->dma_desc_phys_addr | PLX_DMADPR_DESCPCI | - PLX_DMADPR_TCINTR | PLX_DMADPR_XFERL2P; - writel(bits, devpriv->plx9080_mmio + PLX_REG_DMADPR0); - - /* enable dma transfer */ - spin_lock_irqsave(&dev->spinlock, flags); - writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_START | PLX_DMACSR_CLEARINTR, - devpriv->plx9080_mmio + PLX_REG_DMACSR0); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (cmd->stop_src == TRIG_COUNT) - devpriv->dio_count = cmd->stop_arg; - else - devpriv->dio_count = 1; - - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, dev->mmio + BOARD_STATUS_REG); - - /* enable interrupts */ - writel(RX_FULL_INTR, dev->mmio + INTERRUPT_CONTROL_REG); - - writel(RX_ENABLE_BIT, dev->mmio + BOARD_CONTROL_REG); - - return 0; -} - -static int gsc_hpdi_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int i; - - for (i = 0; i < cmd->chanlist_len; i++) { - unsigned int chan = CR_CHAN(cmd->chanlist[i]); - - if (chan != i) { - dev_dbg(dev->class_dev, - "chanlist must be ch 0 to 31 in order\n"); - return -EINVAL; - } - } - - return 0; -} - -static int gsc_hpdi_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - - if (s->io_bits) - return -EINVAL; - - /* Step 1 : check if triggers are trivially valid */ - - err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); - err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= comedi_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); - - if (!cmd->chanlist_len || !cmd->chanlist) { - cmd->chanlist_len = 32; - err |= -EINVAL; - } - err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, - cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); - else /* TRIG_NONE */ - err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* Step 4: fix up any arguments */ - - /* Step 5: check channel list if it exists */ - - if (cmd->chanlist && cmd->chanlist_len > 0) - err |= gsc_hpdi_check_chanlist(dev, s, cmd); - - if (err) - return 5; - - return 0; -} - -/* setup dma descriptors so a link completes every 'len' bytes */ -static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, - unsigned int len) -{ - struct hpdi_private *devpriv = dev->private; - dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; - u32 next_bits = PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR | - PLX_DMADPR_XFERL2P; - unsigned int offset = 0; - unsigned int idx = 0; - unsigned int i; - - if (len > DMA_BUFFER_SIZE) - len = DMA_BUFFER_SIZE; - len -= len % sizeof(u32); - if (len == 0) - return -EINVAL; - - for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { - devpriv->dma_desc[i].pci_start_addr = - cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); - devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); - devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + - (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); - - devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + - (offset / sizeof(u32)); - - offset += len; - if (len + offset > DMA_BUFFER_SIZE) { - offset = 0; - idx++; - } - } - devpriv->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); - - devpriv->block_size = len; - - return len; -} - -static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - - switch (data[0]) { - case INSN_CONFIG_BLOCK_SIZE: - ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); - if (ret) - return ret; - - data[1] = ret; - break; - default: - ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); - if (ret) - return ret; - break; - } - - return insn->n; -} - -static void gsc_hpdi_free_dma(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct hpdi_private *devpriv = dev->private; - int i; - - if (!devpriv) - return; - - /* free pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - if (devpriv->dio_buffer[i]) - dma_free_coherent(&pcidev->dev, - DMA_BUFFER_SIZE, - devpriv->dio_buffer[i], - devpriv->dio_buffer_phys_addr[i]); - } - /* free dma descriptors */ - if (devpriv->dma_desc) - dma_free_coherent(&pcidev->dev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - devpriv->dma_desc, - devpriv->dma_desc_phys_addr); -} - -static int gsc_hpdi_init(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - u32 plx_intcsr_bits; - - /* wait 10usec after reset before accessing fifos */ - writel(BOARD_RESET_BIT, dev->mmio + BOARD_CONTROL_REG); - usleep_range(10, 1000); - - writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), - dev->mmio + RX_PROG_ALMOST_REG); - writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), - dev->mmio + TX_PROG_ALMOST_REG); - - devpriv->tx_fifo_size = readl(dev->mmio + TX_FIFO_SIZE_REG) & - FIFO_SIZE_MASK; - devpriv->rx_fifo_size = readl(dev->mmio + RX_FIFO_SIZE_REG) & - FIFO_SIZE_MASK; - - writel(0, dev->mmio + INTERRUPT_CONTROL_REG); - - /* enable interrupts */ - plx_intcsr_bits = - PLX_INTCSR_LSEABORTEN | PLX_INTCSR_LSEPARITYEN | PLX_INTCSR_PIEN | - PLX_INTCSR_PLIEN | PLX_INTCSR_PABORTIEN | PLX_INTCSR_LIOEN | - PLX_INTCSR_DMA0IEN; - writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_REG_INTCSR); - - return 0; -} - -static void gsc_hpdi_init_plx9080(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - u32 bits; - void __iomem *plx_iobase = devpriv->plx9080_mmio; - -#ifdef __BIG_ENDIAN - bits = PLX_BIGEND_DMA0 | PLX_BIGEND_DMA1; -#else - bits = 0; -#endif - writel(bits, devpriv->plx9080_mmio + PLX_REG_BIGEND); - - writel(0, devpriv->plx9080_mmio + PLX_REG_INTCSR); - - gsc_hpdi_abort_dma(dev, 0); - gsc_hpdi_abort_dma(dev, 1); - - /* configure dma0 mode */ - bits = 0; - /* enable ready input */ - bits |= PLX_DMAMODE_READYIEN; - /* enable dma chaining */ - bits |= PLX_DMAMODE_CHAINEN; - /* - * enable interrupt on dma done - * (probably don't need this, since chain never finishes) - */ - bits |= PLX_DMAMODE_DONEIEN; - /* - * don't increment local address during transfers - * (we are transferring from a fixed fifo register) - */ - bits |= PLX_DMAMODE_LACONST; - /* route dma interrupt to pci bus */ - bits |= PLX_DMAMODE_INTRPCI; - /* enable demand mode */ - bits |= PLX_DMAMODE_DEMAND; - /* enable local burst mode */ - bits |= PLX_DMAMODE_BURSTEN; - bits |= PLX_DMAMODE_WIDTH_32; - writel(bits, plx_iobase + PLX_REG_DMAMODE0); -} - -static int gsc_hpdi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct hpdi_private *devpriv; - struct comedi_subdevice *s; - int i; - int retval; - - dev->board_name = "pci-hpdi32"; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - retval = comedi_pci_enable(dev); - if (retval) - return retval; - pci_set_master(pcidev); - - devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); - dev->mmio = pci_ioremap_bar(pcidev, 2); - if (!devpriv->plx9080_mmio || !dev->mmio) { - dev_warn(dev->class_dev, "failed to remap io memory\n"); - return -ENOMEM; - } - - gsc_hpdi_init_plx9080(dev); - - /* get irq */ - if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, - dev->board_name, dev)) { - dev_warn(dev->class_dev, - "unable to allocate irq %u\n", pcidev->irq); - return -EINVAL; - } - dev->irq = pcidev->irq; - - dev_dbg(dev->class_dev, " irq %u\n", dev->irq); - - /* allocate pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - devpriv->dio_buffer[i] = - dma_alloc_coherent(&pcidev->dev, DMA_BUFFER_SIZE, - &devpriv->dio_buffer_phys_addr[i], - GFP_KERNEL); - if (!devpriv->dio_buffer[i]) { - dev_warn(dev->class_dev, - "failed to allocate DMA buffer\n"); - return -ENOMEM; - } - } - /* allocate dma descriptors */ - devpriv->dma_desc = dma_alloc_coherent(&pcidev->dev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - &devpriv->dma_desc_phys_addr, - GFP_KERNEL); - if (!devpriv->dma_desc) { - dev_warn(dev->class_dev, - "failed to allocate DMA descriptors\n"); - return -ENOMEM; - } - if (devpriv->dma_desc_phys_addr & 0xf) { - dev_warn(dev->class_dev, - " dma descriptors not quad-word aligned (bug)\n"); - return -EIO; - } - - retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); - if (retval < 0) - return retval; - - retval = comedi_alloc_subdevices(dev, 1); - if (retval) - return retval; - - /* Digital I/O subdevice */ - s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | - SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = gsc_hpdi_dio_insn_config; - s->do_cmd = gsc_hpdi_cmd; - s->do_cmdtest = gsc_hpdi_cmd_test; - s->cancel = gsc_hpdi_cancel; - - return gsc_hpdi_init(dev); -} - -static void gsc_hpdi_detach(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->plx9080_mmio) { - writel(0, devpriv->plx9080_mmio + PLX_REG_INTCSR); - iounmap(devpriv->plx9080_mmio); - } - if (dev->mmio) - iounmap(dev->mmio); - } - comedi_pci_disable(dev); - gsc_hpdi_free_dma(dev); -} - -static struct comedi_driver gsc_hpdi_driver = { - .driver_name = "gsc_hpdi", - .module = THIS_MODULE, - .auto_attach = gsc_hpdi_auto_attach, - .detach = gsc_hpdi_detach, -}; - -static int gsc_hpdi_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return comedi_pci_auto_config(dev, &gsc_hpdi_driver, id->driver_data); -} - -static const struct pci_device_id gsc_hpdi_pci_table[] = { - { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, - PCI_VENDOR_ID_PLX, 0x2400) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table); - -static struct pci_driver gsc_hpdi_pci_driver = { - .name = "gsc_hpdi", - .id_table = gsc_hpdi_pci_table, - .probe = gsc_hpdi_pci_probe, - .remove = comedi_pci_auto_unconfig, -}; -module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver); - -MODULE_AUTHOR("Comedi https://www.comedi.org"); -MODULE_DESCRIPTION("Comedi driver for General Standards PCI-HPDI32/PMC-HPDI32"); -MODULE_LICENSE("GPL"); |