📄 pci550x.c
字号:
timeout = interruptible_sleep_on_timeout(&dib->adc_wq, dib->adc_timeout); if (signal_pending(current)) return(-ERESTARTSYS); if (dib->int_status & INT_STATUS_DA0ERR) return(-EIO); if (dib->adc_status & AD_STATUS_ERROR) return (-EIO); } /* process next ADC DMA Buffer */ if (!(dib->adc_status & AD_STATUS_MPRF0)) { pci_dma_sync_single(dib->pdev, dib->adc_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_FROMDEVICE); bytes = copy_to_user((void *)buff, (void *)(dib->adc_dma_buf0 + *offp), count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->adc_dma_bytes)) { dib->adc_status |= AD_STATUS_MPRF0; AD_STATUS_W(dib->adc_status); *offp = 0; } return(count); } } else if (!(dib->adc_status & AD_STATUS_MPRF1)) { pci_dma_sync_single(dib->pdev, dib->adc_dma_handle1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_FROMDEVICE); bytes = copy_to_user((void *)buff, (void *)(dib->adc_dma_buf1 + *offp), count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->adc_dma_bytes)) { dib->adc_status |= AD_STATUS_MPRF1; AD_STATUS_W(dib->adc_status); *offp = 0; } return(count); } } else return(-ETIME);}/* * pci550x_readv - readv method (ADC Scatter-Gather DMA) */static ssize_t pci550x_readv(struct file* filp, const struct iovec* iovp, unsigned long count, loff_t *offp){ return(0);}/* * pci550x_write - write method (DAC Ping-Pong DMA) */static ssize_t pci550x_write(struct file* filp, const char *buff, size_t count, loff_t *offp){ pci550x_dib *dib = (pci550x_dib *)filp->private_data; pci550x_hwregs *REGS = (pci550x_hwregs *)dib->membase; unsigned long bytes; long timeout; if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) return(-ENODEV); /* Process selected DAC */ if (dib->dac_select == PCI550X_DAC0) { /* DAC0 */ /* can't write more than one buffer at a time */ if (count > ((dib->dac0_dma_bytes) - *offp)) count = ((dib->dac0_dma_bytes) - *offp); /* process next DMA write Buffer */ if (dib->dac0_status & DA0_STATUS_ERROR) return(-EIO); else if ( (dib->dac0_status & DA0_STATUS_MPRF0) && (dib->dac0_status & DA0_STATUS_MPRF1) ) { timeout = interruptible_sleep_on_timeout(&dib->dac0_wq, dib->dac0_timeout); if (signal_pending(current)) return(-ERESTARTSYS); if (dib->int_status & INT_STATUS_DA0ERR) return(-EIO); if (dib->dac0_status & DA0_STATUS_ERROR) return (-EIO); } if (!(dib->dac0_status & DA0_STATUS_MPRF0)) { pci_dma_sync_single(dib->pdev, dib->dac0_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); bytes = copy_from_user((void *)(dib->dac0_dma_buf0 + *offp), (void *)buff, count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->dac0_dma_bytes)) { dib->dac0_status |= DA0_STATUS_MPRF0; DA0_STATUS_W(dib->dac0_status); *offp = 0; } return(count); } } else if (!(dib->dac0_status & DA0_STATUS_MPRF1)) { pci_dma_sync_single(dib->pdev, dib->dac0_dma_handle1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); bytes = copy_from_user((void *)(dib->dac0_dma_buf1 + *offp), (void *)buff, count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->dac0_dma_bytes) ) { dib->dac0_status |= DA0_STATUS_MPRF1; DA0_STATUS_W(dib->dac0_status); *offp = 0; } return(count); } } else return(-ETIME); } else { /* DAC1 */ /* can't write more than one buffer at a time */ if (count > ((dib->dac1_dma_bytes) - *offp)) count = ((dib->dac1_dma_bytes) - *offp); /* process next DMA write Buffer */ if (dib->dac1_status & DA1_STATUS_ERROR) return(-EIO); else if ( (dib->dac1_status & DA1_STATUS_MPRF0) && (dib->dac1_status & DA1_STATUS_MPRF1) ) { timeout = interruptible_sleep_on_timeout(&dib->dac1_wq, dib->dac1_timeout); if (signal_pending(current)) return(-ERESTARTSYS); if (dib->int_status & INT_STATUS_DA1ERR) return(-EIO); if (dib->dac1_status & DA1_STATUS_ERROR) return (-EIO); } if (!(dib->dac1_status & DA1_STATUS_MPRF0)) { pci_dma_sync_single(dib->pdev, dib->dac1_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); bytes = copy_from_user((void *)(dib->dac1_dma_buf0 + *offp), (void *)buff, count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->dac1_dma_bytes)) { dib->dac1_status |= DA1_STATUS_MPRF0; DA1_STATUS_W(dib->dac1_status); *offp = 0; } return(count); } } else if (!(dib->dac1_status & DA1_STATUS_MPRF1)) { pci_dma_sync_single(dib->pdev, dib->dac1_dma_handle1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); bytes = copy_from_user((void *)(dib->dac1_dma_buf1 + *offp), (void *)buff, count); if (bytes) return(-EFAULT); else { *offp += count; if (*offp >= (dib->dac1_dma_bytes)) { dib->dac1_status |= DA1_STATUS_MPRF1; DA1_STATUS_W(dib->dac1_status); *offp = 0; } return(count); } } else return(-ETIME); }}/* * pci550x_writev - writev method (DAC Scatter-Gather DMA) */static ssize_t pci550x_writev(struct file* filp, const struct iovec* iovp, unsigned long count, loff_t *offp){ return(0);}/* * pci550x_ioctl - ioctl method */static int pci550x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0; int ret = 0; int i,j; u_int32_t reg, treg; union { s32 pacer_clockf; u_int16_t pacer_clockh[2]; } u1; pci550x_dib *dib = (pci550x_dib *)filp->private_data; pci550x_hwregs *REGS = (pci550x_hwregs *)dib->membase; /* * extract the type and number bitfields, and don't decode * wrong commands: return ENOTTY (inappropriate IOCTL) before * access ok() */ if (_IOC_TYPE(cmd) != PCI550X_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > PCI550X_IOC_MAXNR) return -ENOTTY; /* * the direction is a bitmask, and VERIFY_WRITE catches R/W * transfers. 'Type' is user oriented, while access_ok() is * kernel oriented, so the concept of read and write is reversed. */ if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd) ); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; /* synchronize access to the board registers */ spin_lock(&dib->reg_lock); switch(cmd) { case PCI550X_IOCRESET: /* board reset */ if ( (ret = pci550x_adc_reset(dib)) ) break; if (dib->pdev->subsystem_device == PCI_SUBSYSTEM_ID_B) { if ( (ret = pci550x_dac0_reset(dib)) ) break; ret = pci550x_dac1_reset(dib); } break; case PCI550X_IOC_DAC0_RESET: /* DAC0 reset */ ret = pci550x_dac0_reset(dib); break; case PCI550X_IOC_DAC1_RESET: /* DAC1 reset */ ret = pci550x_dac1_reset(dib); break; case PCI550X_IOCG_BRD_TYPE: /* query board type */ ret = __put_user(dib->brd_type, (int *)arg); break; case PCI550X_IOC_ADC_RESET: /* reset ADC subsystem */ ret = pci550x_adc_reset(dib); break; case PCI550X_IOCS_AD_CCRAM_D: /* download channel list */ AD_STATUS_R(reg); if (reg & AD_STATUS_GATE) { ret = -EBUSY; break; } if ( (err = copy_from_user((void *)&dib->ccram, (void *)arg, sizeof(adc_ccram) )) ) { ret = -EFAULT; break; } if (dib->ccram.elements == 1) { AD_CCRAM_D_W(dib->ccram.ccram[0], ADC_CCRAM_MAX-1); AD_SADDR_W(0xffff); AD_SADDR_WORK_W(0xffff); } else if ( (dib->ccram.elements > 1) && (dib->ccram.elements <= ADC_CCRAM_MAX) ) { for (i = dib->ccram.elements - 1, j = ADC_CCRAM_MAX-1; i >= 0; i--, j--) AD_CCRAM_D_W(dib->ccram.ccram[i], j); AD_SADDR_W(-dib->ccram.elements); AD_SADDR_WORK_W(-dib->ccram.elements); } else { ret = -EINVAL; break; } AD_CCRAM_I_W; break; case PCI550X_IOCG_AD_CCRAM_D: /* upload channel list */ if ( (err = copy_to_user((void *)arg, (void *)&dib->ccram, sizeof(adc_ccram) )) ) { ret = -EFAULT; break; } break; case PCI550X_IOCS_AD_CCRAM_I: /* load the AD_CCRAM_D */ AD_CCRAM_I_W; break; case PCI550X_IOCG_AD_FIFO: /* read the ADC FIFO */ AD_STATUS_R(reg); if ( (reg & AD_STATUS_FFEN) && (reg & AD_STATUS_FNE) ) ret = put_user(AD_FIFO_R, (u_int32_t *)arg); else if (reg & AD_STATUS_FFEN) ret = -EAGAIN; else ret = -EPERM; break; case PCI550X_IOCT_DAC_SELECT: /* select DAC channel */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) { ret = -ENODEV; break; } switch(arg) { case PCI550X_DAC0: dib->dac_select = PCI550X_DAC0; break; case PCI550X_DAC1: dib->dac_select = PCI550X_DAC1; break; default: ret = -EINVAL; break; } break; case PCI550X_IOCQ_DAC_SELECT: /* Query selected DAC */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) ret = -ENODEV; else ret = dib->dac_select; break; case PCI550X_IOCQ_INT_STATUS: /* latest interrupt status */ ret = dib->int_status; break; case PCI550X_IOCQ_ADC_STATUS: /* latest ADC status */ ret = dib->adc_status; break; case PCI550X_IOCQ_DAC0_STATUS: /* latest DAC0 status */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) ret = -ENODEV; else ret = dib->dac0_status; break; case PCI550X_IOCQ_DAC1_STATUS: /* latest DAC1 status */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) ret = -ENODEV; else ret = dib->dac1_status; break; case PCI550X_IOCS_TMR0_LOAD: /* Load TIMER 0 */ TMR0_CTRL_R(reg); if (reg & TMR0_CTRL_ENA) { ret = -EBUSY; break; } ret = get_user(reg, (u_int32_t *)arg); if (!ret) { if ( (reg > 131070) || (reg < 2) || (reg % 2) ) { ret = -EINVAL; break; } TMR0_WORK_W((65536 - (reg >> 1))); TMR0_W((65536 - (reg >> 1))); } break; case PCI550X_IOCG_TMR0_POLL: /* Poll Timer 0 */ TMR0_CTRL_R(reg); if (reg & TMR0_CTRL_ENA) { TMR0_WORK_POLL(reg); ret = put_user(reg, (int *)arg); } else ret = -EAGAIN; break; case PCI550X_IOCS_TMR1_LOAD: /* Load TIMER 1 */ TMR1_CTRL_R(reg); if (reg & TMR1_CTRL_ENA) { ret = -EBUSY; break; } ret = get_user(reg, (u_int32_t *)arg); if (!ret) { if ( (reg > 131070) || (reg < 2) || (reg % 2) ) { ret = -EINVAL; break; } TMR1_WORK_W((65536 - (reg >> 1))); TMR1_W((65536 - (reg >> 1))); } break; case PCI550X_IOCG_TMR1_POLL: /* Poll Timer 1 */ TMR1_CTRL_R(reg); if (reg & TMR1_CTRL_ENA) { TMR1_WORK_POLL(reg); ret = put_user(reg, (int *)arg); } else ret = -EAGAIN; break; case PCI550X_IOCS_CNTR0_LOAD: /* Load Counter 0 */ CNTR0_CTRL_R(reg); if (reg & CNTR0_CTRL_ENA) { ret = -EBUSY; break; } ret = get_user(reg, (u_int32_t *)arg); if (!ret) { if (reg > 65535) { ret = -EINVAL; break; } CNTR0_WORK_W(reg); CNTR0_W(reg); } break; case PCI550X_IOCG_CNTR0_POLL: /* Poll Counter 0 */ CNTR0_CTRL_R(reg); if (reg & CNTR0_CTRL_ENA) { CNTR0_WORK_POLL(reg); ret = put_user(reg, (int *)arg); CNTR0_CTRL_W(reg & CNT0); } else ret = -EAGAIN; break; case PCI550X_IOCS_CNTR1_LOAD: /* Load Counter 1 */ CNTR1_CTRL_R(reg); if (reg & CNTR1_CTRL_ENA) { ret = -EBUSY; break; } ret = get_user(reg, (u_int32_t *)arg); if (!ret) { if (reg > 65535) { ret = -EINVAL; break; } CNTR1_WORK_W(reg); CNTR1_W(reg); } break; case PCI550X_IOCG_CNTR1_POLL: /* Poll Counter 1 */ CNTR1_CTRL_R(reg); if (reg & CNTR1_CTRL_ENA) { CNTR1_WORK_POLL(reg); ret = put_user(reg, (int *)arg); CNTR1_CTRL_W(reg & CNT1); } else ret = -EAGAIN; break; case PCI550X_IOCS_DA0_FIFO: /* write the DAC0 FIFO */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) { ret = -ENODEV; break; } DA0_STATUS_R(reg); if ((reg & DA0_STATUS_FFEN) && (!(reg & DA0_STATUS_FF)) ) { ret = get_user(reg, (u_int32_t *)arg); if (!ret) DA0_FIFO_W(reg); } else if (reg & DA0_STATUS_FFEN) ret = -EAGAIN; else ret = -EPERM; break; case PCI550X_IOCS_DA1_FIFO: /* write the DAC1 FIFO */ if (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) { ret = -ENODEV; break; } DA1_STATUS_R(reg); if ((reg & DA1_STATUS_FFEN) && (!(reg & DA1_STATUS_FF)) ) { ret = get_user(reg, (u_int32_t *)arg); if (!ret) DA1_FIFO_W(reg); } else if (reg & DA1_STATUS_FFEN) ret = -EAGAIN; else ret = -EPERM; break; case PCI550X_IOCS_DIO_0: /* DIO Port 0 Output */ DIO_CTRL_R(reg); if (reg & DIO_CTRL_DDC0) { ret = get_user(reg, (u_int32_t *)arg); if (!ret) DIO_0_W(reg); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -