📄 das1800.c
字号:
common: 1, do_n_chan: 4, ao_ability: 2, ao_n_chan: 2, range_ai: &range_ai_das1802, },};/* * Useful for shorthand access to the particular board structure */#define thisboard ((das1800_board *)dev->board_ptr)typedef struct{ volatile unsigned int count; /* number of data points left to be taken */ unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ int do_bits; /* digital output bits */ int irq_dma_bits; /* bits for control register b */ /* dma bits for control register b, stored so that dma can be * turned on and off */ int dma_bits; unsigned int dma0; /* dma channels used */ unsigned int dma1; volatile unsigned int dma_current; /* dma channel currently in use */ uint16_t *ai_buf0; /* pointers to dma buffers */ uint16_t *ai_buf1; uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */ unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */ int iobase2; /* secondary io address used for analog out on 'ao' boards */ short ao_update_bits; /* remembers the last write to the 'update' dac */}das1800_private;#define devpriv ((das1800_private *)dev->private)// analog out range for boards with basic analog outstatic comedi_lrange range_ao_1 = { 1, { RANGE(-10, 10), }};// analog out range for 'ao' boards/*static comedi_lrange range_ao_2 = { 2, { RANGE(-10, 10), RANGE(-5, 5), }};*/static comedi_driver driver_das1800={ driver_name: "das1800", module: THIS_MODULE, attach: das1800_attach, detach: das1800_detach, num_names: sizeof(das1800_boards) / sizeof(das1800_board), board_name: das1800_boards, offset: sizeof(das1800_board),};/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_das1800);static int das1800_init_dma( comedi_device *dev, unsigned int dma0, unsigned int dma1 ){ unsigned long flags; // need an irq to do dma if( dev->irq && dma0 ) { //encode dma0 and dma1 into 2 digit hexadecimal for switch switch((dma0 & 0x7) | (dma1 << 4)) { case 0x5: // dma0 == 5 devpriv->dma_bits |= DMA_CH5; break; case 0x6: // dma0 == 6 devpriv->dma_bits |= DMA_CH6; break; case 0x7: // dma0 == 7 devpriv->dma_bits |= DMA_CH7; break; case 0x65: // dma0 == 5, dma1 == 6 devpriv->dma_bits |= DMA_CH5_CH6; break; case 0x76: // dma0 == 6, dma1 == 7 devpriv->dma_bits |= DMA_CH6_CH7; break; case 0x57: // dma0 == 7, dma1 == 5 devpriv->dma_bits |= DMA_CH7_CH5; break; default: printk(" only supports dma channels 5 through 7\n" " Dual dma only allows the following combinations:\n" " dma 5,6 / 6,7 / or 7,5\n"); return -EINVAL; break; } if( request_dma( dma0, driver_das1800.driver_name ) ) { printk( " failed to allocate dma channel %i\n", dma0 ); return -EINVAL; } devpriv->dma0 = dma0; devpriv->dma_current = dma0; if( dma1 ) { if( request_dma( dma1, driver_das1800.driver_name ) ) { printk( " failed to allocate dma channel %i\n", dma1 ); return -EINVAL; } devpriv->dma1 = dma1; } devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); if(devpriv->ai_buf0 == NULL) return -ENOMEM; devpriv->dma_current_buf = devpriv->ai_buf0; if( dma1 ) { devpriv->ai_buf1 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); if(devpriv->ai_buf1 == NULL) return -ENOMEM; } flags = claim_dma_lock(); disable_dma(devpriv->dma0); set_dma_mode(devpriv->dma0, DMA_MODE_READ); if( dma1 ) { disable_dma(devpriv->dma1); set_dma_mode(devpriv->dma1, DMA_MODE_READ); } release_dma_lock(flags); } return 0;}static int das1800_attach(comedi_device *dev, comedi_devconfig *it){ comedi_subdevice *s; int iobase = it->options[0]; int irq = it->options[1]; int dma0 = it->options[2]; int dma1 = it->options[3]; int iobase2; int board; int retval; /* allocate and initialize dev->private */ if(alloc_private(dev, sizeof(das1800_private)) < 0) return -ENOMEM; printk("comedi%d: %s: io 0x%x", dev->minor, driver_das1800.driver_name, iobase); if(irq) { printk(", irq %i", irq); if(dma0) { printk(", dma %i", dma0); if(dma1) printk(" and %i", dma1); } } printk("\n"); if(iobase == 0) { printk(" io base address required\n"); return -EINVAL; } /* check if io addresses are available */ if(check_region(iobase, DAS1800_SIZE) < 0) { printk(" I/O port conflict: failed to allocate ports 0x%x to 0x%x\n", iobase, iobase + DAS1800_SIZE - 1); return -EIO; } request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name); dev->iobase = iobase; board = das1800_probe(dev); if(board < 0) { printk(" unable to determine board type\n"); return -ENODEV; } dev->board_ptr = das1800_boards + board; dev->board_name = thisboard->name; // if it is an 'ao' board with fancy analog out then we need extra io ports if(thisboard->ao_ability == 2) { iobase2 = iobase + IOBASE2; if(check_region(iobase2, DAS1800_SIZE) < 0) { printk(" I/O port conflict: failed to allocate ports 0x%x to 0x%x\n", iobase2, iobase2 + DAS1800_SIZE - 1); return -EIO; } request_region(iobase2, DAS1800_SIZE, driver_das1800.driver_name); devpriv->iobase2 = iobase2; } /* grab our IRQ */ if(irq) { if(comedi_request_irq( irq, das1800_interrupt, 0, driver_das1800.driver_name, dev )) { printk(" unable to allocate irq %d\n", irq); return -EINVAL; } } dev->irq = irq; // set bits that tell card which irq to use switch(irq) { case 0: break; case 3: devpriv->irq_dma_bits |= 0x8; break; case 5: devpriv->irq_dma_bits |= 0x10; break; case 7: devpriv->irq_dma_bits |= 0x18; break; case 10: devpriv->irq_dma_bits |= 0x28; break; case 11: devpriv->irq_dma_bits |= 0x30; break; case 15: devpriv->irq_dma_bits |= 0x38; break; default: printk(" irq out of range\n"); return -EINVAL; break; } retval = das1800_init_dma( dev, dma0, dma1 ); if( retval < 0 ) return retval; if( devpriv->ai_buf0 == NULL ) { devpriv->ai_buf0 = kmalloc( FIFO_SIZE * sizeof( uint16_t ), GFP_KERNEL ); if(devpriv->ai_buf0 == NULL) return -ENOMEM; } if(alloc_subdevices(dev, 4) < 0) return -ENOMEM; /* analog input subdevice */ s = dev->subdevices + 0; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; if(thisboard->common) s->subdev_flags |= SDF_COMMON; s->n_chan = thisboard->qram_len; s->len_chanlist = thisboard->qram_len; s->maxdata = (1 << thisboard->resolution) - 1; s->range_table = thisboard->range_ai; s->do_cmd = das1800_ai_do_cmd; s->do_cmdtest = das1800_ai_do_cmdtest; s->insn_read = das1800_ai_rinsn; s->poll = das1800_ai_poll; s->cancel = das1800_cancel; /* analog out */ s = dev->subdevices + 1; if(thisboard->ao_ability == 1) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->ao_n_chan; s->maxdata = (1 << thisboard->resolution) - 1; s->range_table = &range_ao_1; s->insn_write = das1800_ao_winsn; } else { s->type = COMEDI_SUBD_UNUSED; } /* di */ s = dev->subdevices + 2; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = das1800_di_rbits; /* do */ s = dev->subdevices + 3; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = thisboard->do_n_chan; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = das1800_do_wbits; das1800_cancel(dev, dev->read_subdev); // initialize digital out channels outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); // initialize analog out channels if(thisboard->ao_ability == 1) { // select 'update' dac channel for baseAddress + 0x0 outb(DAC(thisboard->ao_n_chan - 1), dev->iobase + DAS1800_SELECT); outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC); } return 0;};static int das1800_detach(comedi_device *dev){ /* only free stuff if it has been allocated by _attach */ if(dev->iobase) release_region(dev->iobase, DAS1800_SIZE); if(dev->irq) comedi_free_irq(dev->irq, dev); if(dev->private) { if(devpriv->iobase2) release_region(devpriv->iobase2, DAS1800_SIZE); if(devpriv->dma0) free_dma(devpriv->dma0); if(devpriv->dma1) free_dma(devpriv->dma1); if(devpriv->ai_buf0) kfree(devpriv->ai_buf0); if(devpriv->ai_buf1) kfree(devpriv->ai_buf1); } printk("comedi%d: %s: remove\n", dev->minor, driver_das1800.driver_name); return 0;};/* probes and checks das-1800 series board type */static int das1800_probe(comedi_device *dev){ int id; int board; id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf; /* get id bits */ board = ((das1800_board *)dev->board_ptr) - das1800_boards; switch(id) { case 0x3: if(board == das1801st_da || board == das1802st_da || board == das1701st_da || board == das1702st_da) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1800st-da series\n"); return das1801st; break; case 0x4: if(board == das1802hr_da || board == das1702hr_da) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1802hr-da\n"); return das1802hr; break; case 0x5: if(board == das1801ao || board == das1802ao || board == das1701ao || board == das1702ao) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1800ao series\n"); return das1801ao; break; case 0x6: if(board == das1802hr || board == das1702hr) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1802hr\n"); return das1802hr; break; case 0x7: if(board == das1801st || board == das1802st || board == das1701st || board == das1702st) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1800st series\n"); return das1801st; break; case 0x8: if(board == das1801hc || board == das1802hc) { printk(" Board model: %s\n", das1800_boards[board].name); return board; } printk(" Board model (probed, not recommended): das-1800hc series\n"); return das1801hc; break; default : printk(" Board model: probe returned 0x%x (unknown, please report)\n", id); return board; break; } return -1;}static int das1800_ai_poll(comedi_device *dev,comedi_subdevice *s){ unsigned long flags; // prevent race with interrupt handler comedi_spin_lock_irqsave(&dev->spinlock, flags); das1800_ai_handler(dev); comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -