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

📄 amplc_pc263.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
字号:
/*    comedi/drivers/amplc_pc263.c    Driver for Amplicon PC263 and PCI263 relay boards.    Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 2000 David A. Schleef <ds@schleef.org>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//*Driver: amplc_pc263.oDescription: Driver for Amplicon PC263 and PCI263 Relay boardsAuthor: Ian Abbott <abbotti@mev.co.uk>Devices: [Amplicon] PC263 (pc263), PCI263 (pci263)Updated: Tue, 20 Aug 2002 11:41:01 +0100Status: worksConfiguration options - PC263:  [0] - I/O port base addressConfiguration options - PCI263:  [0] - PCI bus of device (optional)  [1] - PCI slot of device (optional)  If bus/slot is not specified, the first available PCI device will be  used.Each board appears as one subdevice, with 16 digital outputs, eachconnected to a reed-relay. Relay contacts are closed when output is 1.The state of the outputs can be read.*/#include <linux/comedidev.h>#include <linux/pci.h>#define PC263_DRIVER_NAME	"amplc_pc263"/* PCI263 PCI configuration register information */#define PCI_VENDOR_ID_AMPLICON 0x14dc#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c/* PC263 / PCI263 registers */#define PC263_IO_SIZE	2/* * Board descriptions for Amplicon PC263 / PCI263. */enum pc263_bustype {isa_bustype, pci_bustype};enum pc263_model {pc263_model, pci263_model};typedef struct pc263_board_struct{	char *name;	char *fancy_name;	enum pc263_bustype bustype;	enum pc263_model model;}pc263_board;static pc263_board pc263_boards[] = {	{	name:		"pc263",	fancy_name:	"PC263",	bustype:	isa_bustype,	model:		pc263_model,	},	{	name:		"pci263",	fancy_name:	"PCI263",	bustype:	pci_bustype,	model:		pci263_model,	},};static struct pci_device_id pc263_pci_table[] __devinitdata = {	{ PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pci263_model },	{ 0 }};MODULE_DEVICE_TABLE(pci, pc263_pci_table);/* * Useful for shorthand access to the particular board structure */#define thisboard ((pc263_board *)dev->board_ptr)/* this structure is for data unique to this hardware driver.  If   several hardware drivers keep similar information in this structure,   feel free to suggest moving the variable to the comedi_device struct.  */typedef struct{	/* PCI device. */	struct pci_dev *pci_dev;}pc263_private;#define devpriv ((pc263_private *)dev->private)/* * The comedi_driver structure tells the Comedi core module * which functions to call to configure/deconfigure (attach/detach) * the board, and also about the kernel module that contains * the device code. */static int pc263_attach(comedi_device *dev,comedi_devconfig *it);static int pc263_detach(comedi_device *dev);static comedi_driver driver_amplc_pc263={	driver_name:	PC263_DRIVER_NAME,	module:		THIS_MODULE,	attach:		pc263_attach,	detach:		pc263_detach,	board_name:	pc263_boards,	offset:		sizeof(pc263_board),	num_names:	sizeof(pc263_boards) / sizeof(pc263_board),};static int pc263_request_region(unsigned long from, unsigned long extent);static int pc263_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data);static int pc263_dio_insn_config(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data);/* * Attach is called by the Comedi core to configure the driver * for a particular board.  If you specified a board_name array * in the driver structure, dev->board_ptr contains that * address. */static int pc263_attach(comedi_device *dev,comedi_devconfig *it){	comedi_subdevice *s;	struct pci_dev *pci_dev = NULL;	int iobase = 0;	int bus = 0, slot = 0;	struct pci_device_id *pci_id;	int ret;	printk("comedi%d: %s: ",dev->minor, PC263_DRIVER_NAME);	/* Get card bus position and base address. */	switch (thisboard->bustype) {	case isa_bustype:		iobase = it->options[0];		break;	case pci_bustype:		bus = it->options[0];		slot = it->options[1];		/* Look for PCI table entry for this model. */		for (pci_id = pc263_pci_table; pci_id->vendor != 0; pci_id++) {			if (pci_id->driver_data == thisboard->model)				break;		}		if (pci_id->driver_data != thisboard->model) {			printk("bug! cannot determine board type!\n");			return -EINVAL;		}		/* Look for matching PCI device. */		pci_for_each_dev(pci_dev) {			/* If bus/slot specified, check them. */			if (bus || slot) {				if (bus != pci_dev->bus->number						|| slot != PCI_SLOT(pci_dev->devfn))					continue;			}			if (pci_dev->vendor != pci_id->vendor)				continue;			if (pci_dev->device != pci_id->device)				continue;#if 0			if (pci_id->subvendor != PCI_ANY_ID) {				if (pci_dev->subsystem_vendor != pci_id->subvendor)					continue;			}			if (pci_id->subdevice != PCI_ANY_ID) {				if (pci_dev->subsystem_device != pci_id->subdevice)					continue;			}#endif			if (((pci_dev->class ^ pci_id->class) & pci_id->class_mask) != 0)				continue;			/* Found a match. */			break;		}		if (!pci_dev) {			printk("no %s found!\n", thisboard->fancy_name);			return -EIO;		}		if ((ret=pci_enable_device(pci_dev)) < 0) {			printk("error enabling PCI device!\n");			return ret;		}		iobase = pci_resource_start(pci_dev, 2);		break;	default:		printk("bug! cannot determine board type!\n");		return -EINVAL;		break;	}/* * Initialize dev->board_name. */	dev->board_name = thisboard->name;	printk("%s ", dev->board_name);/* * Allocate the private structure area.  alloc_private() is a * convenient macro defined in comedidev.h. */	if ((ret=alloc_private(dev,sizeof(pc263_private))) < 0) {		printk("out of memory!\n");		return ret;	}	devpriv->pci_dev = pci_dev;	/* Reserve I/O space. */	if ((ret=pc263_request_region(iobase, PC263_IO_SIZE)) < 0) {		return ret;	}	dev->iobase = iobase;/* * Allocate the subdevice structures.  alloc_subdevice() is a * convenient macro defined in comedidev.h. */	if ((ret=alloc_subdevices(dev, 1)) < 0) {		printk("out of memory!\n");		return -ENOMEM;	}	s = dev->subdevices+0;	/* digital i/o subdevice */	s->type = COMEDI_SUBD_DIO;	s->subdev_flags = SDF_READABLE|SDF_WRITABLE|SDF_RT;	s->n_chan = 16;	s->maxdata = 1;	s->range_table = &range_digital;	s->insn_bits = pc263_dio_insn_bits;	s->insn_config = pc263_dio_insn_config;	/* all outputs */	s->io_bits = 0xffff;	/* read initial relay state */	s->state = inb(dev->iobase);	s->state = s->state | (inb(dev->iobase) << 8);	if (thisboard->bustype == isa_bustype) {		printk("(base %#x) ", iobase);	} else {		printk("(pci %02x:%02x.%x) ", pci_dev->bus->number,				PCI_SLOT(pci_dev->devfn),				PCI_FUNC(pci_dev->devfn));	}		printk("attached\n");	return 1;}/* * _detach is called to deconfigure a device.  It should deallocate * resources.   * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach().  dev->private and dev->subdevices are * deallocated automatically by the core. */static int pc263_detach(comedi_device *dev){	printk("comedi%d: %s: remove\n", dev->minor, PC263_DRIVER_NAME);	if (dev->iobase)		release_region(dev->iobase, PC263_IO_SIZE);		return 0;}/* * This function checks and requests an I/O region, reporting an error * if there is a conflict. */static int pc263_request_region(unsigned long from, unsigned long extent){	if (check_region(from, extent) < 0) {		printk("I/O port conflict (%#lx,%lu)!\n", from, extent);		return -EIO;	}	request_region(from, extent, PC263_DRIVER_NAME);	return 0;}/* DIO devices are slightly special.  Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels.  The * comedi core can convert between insn_bits and insn_read/write */static int pc263_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(insn->n!=2)return -EINVAL;	/* The insn data is a mask in data[0] and the new data	 * in data[1], each channel cooresponding to a bit. */	if(data[0]){		s->state &= ~data[0];		s->state |= data[0]&data[1];		/* Write out the new digital output lines */		outb(s->state & 0xFF, dev->iobase);		outb(s->state >> 8, dev->iobase + 1);	}	/* on return, data[1] contains the value of the digital	 * input and output lines. */	/* or we could just return the software copy of the output values if	 * it was a purely digital output subdevice */	data[1]=s->state;	return 2;}static int pc263_dio_insn_config(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(insn->n!=1)return -EINVAL;	return 1;}/* * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */COMEDI_INITCLEANUP(driver_amplc_pc263);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -