⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adl_pci9111.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
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 + -