📄 adl_pci9111.c
字号:
static void pci9111_pretrigger_set (comedi_device *dev, bool pretrigger){ int flags; flags = pci9111_trigger_and_autoscan_get () & 0x07; if (pretrigger) flags |= PCI9111_PTRG_ON; pci9111_trigger_and_autoscan_set (flags);}static void pci9111_autoscan_set (comedi_device *dev, bool autoscan){ int flags; flags = pci9111_trigger_and_autoscan_get() & 0x0e; if (autoscan) flags |= PCI9111_ASCAN_ON; pci9111_trigger_and_autoscan_set (flags);}typedef enum { irq_on_eoc, irq_on_fifo_half_full}pci9111_ISC0_sources;typedef enum{ irq_on_timer_tick, irq_on_external_trigger} pci9111_ISC1_sources;static void pci9111_interrupt_source_set (comedi_device *dev, pci9111_ISC0_sources irq_0_source, pci9111_ISC1_sources irq_1_source){ int flags; flags = pci9111_interrupt_and_fifo_get() & 0x04; if (irq_0_source == irq_on_fifo_half_full) flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL; if (irq_1_source == irq_on_external_trigger) flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG; pci9111_interrupt_and_fifo_set (flags);}// ------------------------------------------------------------------// // HARDWARE TRIGGERED ANALOG INPUT SECTION// // ------------------------------------------------------------------//// Cancel analog input autoscan//#undef AI_DO_CMD_DEBUGstatic int pci9111_ai_cancel ( comedi_device *dev, comedi_subdevice *s){ // Disable interrupts plx9050_interrupt_control (dev_private->lcr_io_base, true, true, true, true, false); pci9111_trigger_source_set (dev, software); pci9111_autoscan_set (dev, false); pci9111_fifo_reset(); #ifdef AI_DO_CMD_DEBUG printk (PCI9111_DRIVER_NAME ": ai_cancel\n");#endif return 0;}//// Test analog input command// #define pci9111_check_trigger_src(src,flags) \ tmp = src; \ src &= flags; \ if (!src || tmp != src) error++ static int pci9111_ai_do_cmd_test ( comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd){ int tmp; int error=0; int range, reference; int i; int rounded_timer; pci9111_board_struct* board= (pci9111_board_struct*) dev->board_ptr; // Step 1 : check if trigger are trivialy valid pci9111_check_trigger_src (cmd->start_src, TRIG_NOW); pci9111_check_trigger_src (cmd->scan_begin_src, TRIG_TIMER|TRIG_FOLLOW|TRIG_EXT); pci9111_check_trigger_src (cmd->convert_src, TRIG_TIMER|TRIG_EXT); pci9111_check_trigger_src (cmd->scan_end_src, TRIG_COUNT); pci9111_check_trigger_src (cmd->stop_src, TRIG_COUNT|TRIG_NONE); if (error) return 1; // step 2 : make sure trigger sources are unique and mutually compatible if (cmd->start_src != TRIG_NOW) error++; if ((cmd->scan_begin_src != TRIG_TIMER) && (cmd->scan_begin_src != TRIG_FOLLOW) && (cmd->scan_begin_src != TRIG_EXT)) error++; if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) { error++; } if ((cmd->convert_src == TRIG_TIMER) && !((cmd->scan_begin_src == TRIG_TIMER) || (cmd->scan_begin_src == TRIG_FOLLOW))) { error++; } if ((cmd->convert_src == TRIG_EXT) && !((cmd->scan_begin_src == TRIG_EXT) || (cmd->scan_begin_src == TRIG_FOLLOW))) { error++; } if (cmd->scan_end_src != TRIG_COUNT) error++; if ( (cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE)) error++; if (error) return 2; // Step 3 : make sure arguments are trivialy compatible if (cmd->chanlist_len<1) { cmd->chanlist_len=1; error++; } if (cmd->chanlist_len>board->ai_channel_nbr) { cmd->chanlist_len=board->ai_channel_nbr; error++; } if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg!=0)) { cmd->start_arg=0; error++; } if ((cmd->convert_src == TRIG_TIMER) && (cmd->convert_arg<board->ai_acquisition_period_min_ns)) { cmd->convert_arg=board->ai_acquisition_period_min_ns; error++; } if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) { cmd->convert_arg = 0; error++; } if ((cmd->scan_begin_src == TRIG_TIMER) && (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) { cmd->scan_begin_arg = board->ai_acquisition_period_min_ns; error++; } if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) { cmd->scan_begin_arg = 0; error++; } if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) { cmd->scan_begin_arg = 0; error++; } if ((cmd->scan_end_src == TRIG_COUNT) && (cmd->scan_end_arg != cmd->chanlist_len)) { cmd->scan_end_arg=cmd->chanlist_len; error++; } if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) { cmd->stop_arg=1; error++; } if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg !=0)) { cmd->stop_arg=0; error++; } if (error) return 3; // Step 4 : fix up any arguments if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; i8253_cascade_ns_to_timer_2div (PCI9111_8254_CLOCK_PERIOD_NS, &(dev_private->timer_divisor_1), &(dev_private->timer_divisor_2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK); if (tmp != cmd->convert_arg) error++; } // There's only one timer on this card, so the scan_begin timer must // be a multiple of chanlist_len*convert_arg if (cmd->scan_begin_src == TRIG_TIMER) { rounded_timer = (cmd->scan_begin_arg / (cmd->chanlist_len * cmd->convert_arg)) * (cmd->chanlist_len * cmd->convert_arg); if (cmd->scan_begin_arg != rounded_timer) { cmd->scan_begin_arg = rounded_timer; error++; } if (cmd->scan_begin_arg < cmd->convert_arg ) { cmd->scan_begin_arg = cmd->convert_arg; error++; } } if (error) return 4; // Step 5 : check channel list if (cmd->chanlist) { range=CR_RANGE(cmd->chanlist[0]); reference=CR_AREF(cmd->chanlist[0]); if (cmd->chanlist_len > 1) { for (i=0;i<cmd->chanlist_len;i++) { if (CR_CHAN(cmd->chanlist[i]) != i) { comedi_error (dev, "entries in chanlist must be consecutive " "channels,counting upwards from 0\n"); error++; } if (CR_RANGE(cmd->chanlist[i]) != range) { comedi_error (dev, "entries in chanlist must all have the same gain\n"); error++; } if (CR_AREF(cmd->chanlist[i]) != reference) { comedi_error (dev, "entries in chanlist must all have the same reference\n"); error++; } } } else { if ((CR_CHAN (cmd->chanlist[0]) > (board->ai_channel_nbr -1)) || (CR_CHAN (cmd->chanlist[0]) < 0)) { comedi_error (dev, "channel number is out of limits\n"); error++; } } } if (error) return 5; return 0; }//// Analog input command//static int pci9111_ai_do_cmd ( comedi_device *dev, comedi_subdevice *subdevice) { comedi_cmd *async_cmd=&subdevice->async->cmd; if (!dev->irq) { comedi_error (dev, "no irq assigned for PCI9111, cannot do hardware conversion"); return -1; } // Set channel scan limit // // PCI9111 allows only scanning from channel 0 to channel n // // TODO: handle the case of an external multilexer // if (async_cmd->chanlist_len>1) { pci9111_ai_channel_set ((async_cmd->chanlist_len)-1); pci9111_autoscan_set (dev, true); } else { pci9111_ai_channel_set (CR_CHAN (async_cmd->chanlist[0])); pci9111_autoscan_set (dev, false); } // Set gain // // This is the same gain on every channel // pci9111_ai_range_set (CR_RANGE(async_cmd->chanlist[0])); // Set counter switch (async_cmd->stop_src) { case TRIG_COUNT: dev_private->stop_counter = async_cmd->stop_arg * async_cmd->chanlist_len; dev_private->stop_is_none = 0; break; case TRIG_NONE: dev_private->stop_counter = 0; dev_private->stop_is_none = 1; break; default: comedi_error(dev, "Invalid stop trigger"); return -1; } dev_private->scan_begin_counter=0; // Set timer pacer switch (async_cmd->convert_src) { case TRIG_TIMER: i8253_cascade_ns_to_timer_2div (PCI9111_8254_CLOCK_PERIOD_NS, &(dev_private->timer_divisor_1), &(dev_private->timer_divisor_2), &(async_cmd->convert_arg), async_cmd->flags & TRIG_ROUND_MASK);#ifdef AI_DO_CMD_DEBUG printk (PCI9111_DRIVER_NAME ": divisors = %d, %d\n", dev_private->timer_divisor_1,dev_private->timer_divisor_2);#endif if (async_cmd->scan_begin_src == TRIG_TIMER) { dev_private->scan_begin_counter_limit = async_cmd->scan_begin_arg / async_cmd->convert_arg; } else { dev_private->scan_begin_counter_limit = async_cmd->chanlist_len; } pci9111_trigger_source_set (dev,software); pci9111_timer_set (dev); pci9111_fifo_reset (); pci9111_interrupt_source_set (dev,irq_on_fifo_half_full, irq_on_timer_tick); pci9111_trigger_source_set (dev,timer_pacer); plx9050_interrupt_control (dev_private->lcr_io_base, true, true, false, true, true); break; case TRIG_EXT : dev_private->scan_begin_counter_limit = async_cmd->chanlist_len; pci9111_trigger_source_set (dev, external); pci9111_fifo_reset (); pci9111_interrupt_source_set (dev, irq_on_fifo_half_full, irq_on_timer_tick); plx9050_interrupt_control (dev_private->lcr_io_base, true, true, false, true, true); break; default : comedi_error (dev, "Invalid convert trigger"); return -1; }#ifdef AI_DO_CMD_DEBUG printk (PCI9111_DRIVER_NAME ": start interruptions!\n"); printk (PCI9111_DRIVER_NAME ": trigger source=%2x\n", pci9111_trigger_and_autoscan_get()); printk (PCI9111_DRIVER_NAME ": irq source=%2x\n", pci9111_interrupt_and_fifo_get()); printk (PCI9111_DRIVER_NAME ": ai_do_cmd\n"); printk (PCI9111_DRIVER_NAME ": stop_counter=%d\n", dev_private->stop_counter); printk (PCI9111_DRIVER_NAME ": scan_begin_counter_limit=%d\n", dev_private->scan_begin_counter_limit);#endif return 0;}// ------------------------------------------------------------------// // INTERRUPT SECTION// // ------------------------------------------------------------------#undef INTERRUPT_DEBUGstatic void pci9111_interrupt (int irq, void *p_device, struct pt_regs *regs){ comedi_device *dev=p_device; comedi_subdevice *subdevice = dev->read_subdev; comedi_async *async; unsigned long irq_flags; int i, data; int resolution = ((pci9111_board_struct *) dev->board_ptr)->ai_resolution; async = subdevice->async; comedi_spin_lock_irqsave (&dev->spinlock, irq_flags); if ((inb(dev_private->lcr_io_base+PLX9050_REGISTER_INTERRUPT_CONTROL) & PLX9050_LINTI1_STATUS) != 0) { // Interrupt comes from fifo_half-full signal if (pci9111_is_fifo_full()) { comedi_spin_unlock_irqrestore (&dev->spinlock, irq_flags); comedi_error (dev, PCI9111_DRIVER_NAME " fifo overflow"); pci9111_interrupt_clear(); pci9111_ai_cancel (dev, subdevice); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_event (dev, subdevice, async->events); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -