static int pcl812_attach()

in drivers/pcl812.c [1128:1313]


static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
	const struct pcl812_board *board = dev->board_ptr;
	struct pcl812_private *devpriv;
	struct comedi_subdevice *s;
	int n_subdevices;
	int subdev;
	int ret;

	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
	if (!devpriv)
		return -ENOMEM;

	ret = comedi_request_region(dev, it->options[0], 0x10);
	if (ret)
		return ret;

	if (board->irq_bits) {
		dev->pacer = comedi_8254_init(dev->iobase + PCL812_TIMER_BASE,
					      I8254_OSC_BASE_2MHZ,
					      I8254_IO8, 0);
		if (!dev->pacer)
			return -ENOMEM;

		if ((1 << it->options[1]) & board->irq_bits) {
			ret = request_irq(it->options[1], pcl812_interrupt, 0,
					  dev->board_name, dev);
			if (ret == 0)
				dev->irq = it->options[1];
		}
	}

	/* we need an IRQ to do DMA on channel 3 or 1 */
	if (dev->irq && board->has_dma)
		pcl812_alloc_dma(dev, it->options[2]);

	/* differential analog inputs? */
	switch (board->board_type) {
	case BOARD_A821:
		if (it->options[2] == 1)
			devpriv->use_diff = 1;
		break;
	case BOARD_ACL8112:
	case BOARD_ACL8216:
		if (it->options[4] == 1)
			devpriv->use_diff = 1;
		break;
	default:
		break;
	}

	n_subdevices = 1;		/* all boardtypes have analog inputs */
	if (board->n_aochan > 0)
		n_subdevices++;
	if (board->has_dio)
		n_subdevices += 2;

	ret = comedi_alloc_subdevices(dev, n_subdevices);
	if (ret)
		return ret;

	subdev = 0;

	/* Analog Input subdevice */
	s = &dev->subdevices[subdev];
	s->type		= COMEDI_SUBD_AI;
	s->subdev_flags	= SDF_READABLE;
	if (devpriv->use_diff) {
		s->subdev_flags	|= SDF_DIFF;
		s->n_chan	= board->n_aichan / 2;
	} else {
		s->subdev_flags	|= SDF_GROUND;
		s->n_chan	= board->n_aichan;
	}
	s->maxdata	= board->has_16bit_ai ? 0xffff : 0x0fff;

	pcl812_set_ai_range_table(dev, s, it);

	s->insn_read	= pcl812_ai_insn_read;

	if (dev->irq) {
		dev->read_subdev = s;
		s->subdev_flags	|= SDF_CMD_READ;
		s->len_chanlist	= MAX_CHANLIST_LEN;
		s->do_cmdtest	= pcl812_ai_cmdtest;
		s->do_cmd	= pcl812_ai_cmd;
		s->poll		= pcl812_ai_poll;
		s->cancel	= pcl812_ai_cancel;
	}

	devpriv->use_mpc508 = board->has_mpc508_mux;

	subdev++;

	/* analog output */
	if (board->n_aochan > 0) {
		s = &dev->subdevices[subdev];
		s->type		= COMEDI_SUBD_AO;
		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
		s->n_chan	= board->n_aochan;
		s->maxdata	= 0xfff;
		switch (board->board_type) {
		case BOARD_A821:
			if (it->options[3] == 1)
				s->range_table = &range_unipolar10;
			else
				s->range_table = &range_unipolar5;
			break;
		case BOARD_PCL812:
		case BOARD_ACL8112:
		case BOARD_PCL812PG:
		case BOARD_ACL8216:
			switch (it->options[5]) {
			case 1:
				s->range_table = &range_unipolar10;
				break;
			case 2:
				s->range_table = &range_unknown;
				break;
			default:
				s->range_table = &range_unipolar5;
				break;
			}
			break;
		default:
			s->range_table = &range_unipolar5;
			break;
		}
		s->insn_write	= pcl812_ao_insn_write;

		ret = comedi_alloc_subdev_readback(s);
		if (ret)
			return ret;

		subdev++;
	}

	if (board->has_dio) {
		/* Digital Input subdevice */
		s = &dev->subdevices[subdev];
		s->type		= COMEDI_SUBD_DI;
		s->subdev_flags	= SDF_READABLE;
		s->n_chan	= 16;
		s->maxdata	= 1;
		s->range_table	= &range_digital;
		s->insn_bits	= pcl812_di_insn_bits;
		subdev++;

		/* Digital Output subdevice */
		s = &dev->subdevices[subdev];
		s->type		= COMEDI_SUBD_DO;
		s->subdev_flags	= SDF_WRITABLE;
		s->n_chan	= 16;
		s->maxdata	= 1;
		s->range_table	= &range_digital;
		s->insn_bits	= pcl812_do_insn_bits;
		subdev++;
	}

	switch (board->board_type) {
	case BOARD_ACL8216:
	case BOARD_PCL812PG:
	case BOARD_PCL812:
	case BOARD_ACL8112:
		devpriv->max_812_ai_mode0_rangewait = 1;
		if (it->options[3] > 0)
						/*  we use external trigger */
			devpriv->use_ext_trg = 1;
		break;
	case BOARD_A821:
		devpriv->max_812_ai_mode0_rangewait = 1;
		devpriv->mode_reg_int = (dev->irq << 4) & 0xf0;
		break;
	case BOARD_PCL813B:
	case BOARD_PCL813:
	case BOARD_ISO813:
	case BOARD_ACL8113:
		/* maybe there must by greatest timeout */
		devpriv->max_812_ai_mode0_rangewait = 5;
		break;
	}

	pcl812_reset(dev);

	return 0;
}