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

📄 comedi_parport.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
字号:
/*    comedi/drivers/comedi_parport.c    hardware driver for standard parallel port    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1998,2001 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: comedi_parport.oDescription: Standard PC parallel portAuthor: dsStatus: works in immediate modeDevices: [standard] parallel port (comedi_parport)Updated: Tue, 30 Apr 2002 21:11:45 -0700A cheap and easy way to get a few more digital I/O lines.  Stealadditional parallel ports from old computers or your neighbors'computers.Option list: 0: I/O port base for the parallel port. 1: IRQParallel Port Lines:pin     subdev  chan    aka---     ------  ----    ---1       2       0       strobe2       0       0       data 03       0       1       data 14       0       2       data 25       0       3       data 36       0       4       data 47       0       5       data 58       0       6       data 69       0       7       data 710      1       3       acknowledge11      1       4       busy12      1       2       output13      1       1       printer selected14      2       1       auto LF15      1       0       error16      2       2       init17      2       3       select printer18-25   groundNotes:Subdevices 0 is digital I/O, subdevice 1 is digital input, andsubdevice 2 is digital output.  Unlike other Comedi devices,subdevice 0 defaults to output.Pins 13 and 14 are inverted once by Comedi and once by thehardware, thus cancelling the effect.Pin 1 is a strobe, thus acts like one.  There's no way in softwareto change this, at least on a standard parallel port.Subdevice 3 pretends to be a digital input subdevice, but it alwaysreturns 0 when read.  However, if you run a command withscan_begin_src=TRIG_EXT, it uses pin 10 as a external triggeringpin, which can be used to wake up tasks.*//*   see http://www.beyondlogic.org/ for information.   or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html */#include <linux/comedidev.h>#include <linux/ioport.h>#define PARPORT_SIZE 3#define PARPORT_A 0#define PARPORT_B 1#define PARPORT_C 2static int parport_attach(comedi_device *dev,comedi_devconfig *it);static int parport_detach(comedi_device *dev);static comedi_driver driver_parport={	driver_name:	"comedi_parport",	module:		THIS_MODULE,	attach:		parport_attach,	detach:		parport_detach,};COMEDI_INITCLEANUP(driver_parport);typedef struct parport_private_struct{	unsigned int a_data;	unsigned int c_data;	int enable_irq;}parport_private;#define devpriv ((parport_private *)(dev->private))static int parport_insn_a(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(data[0]){		devpriv->a_data &= ~data[0];		devpriv->a_data |= (data[0]&data[1]);		outb(devpriv->a_data,dev->iobase+PARPORT_A);	}	data[1] = inb(devpriv->a_data);	return 2;}	static int parport_insn_config_a(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(data[0]){		s->io_bits = 0xff;		devpriv->c_data &= ~(1<<5);	}else{		s->io_bits = 0;		devpriv->c_data |= (1<<5);	}	outb(devpriv->c_data,dev->iobase+PARPORT_C);	return 1;}	static int parport_insn_b(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(data[0]){		// should writes be ignored?	}	data[1] = (inb(dev->iobase+PARPORT_B)>>3);	return 2;}static int parport_insn_c(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	data[0] &= 0x0f;	if(data[0]){		devpriv->c_data &= ~data[0];		devpriv->c_data |= (data[0]&data[1]);		outb(devpriv->c_data,dev->iobase+PARPORT_C);	}	data[1] = devpriv->c_data & 0xf;	return 2;}static int parport_intr_insn(comedi_device *dev,comedi_subdevice *s,	comedi_insn *insn,lsampl_t *data){	if(insn->n<1)return -EINVAL;	data[1] = 0;	return 2;}static int parport_intr_cmdtest(comedi_device *dev,comedi_subdevice *s,	comedi_cmd *cmd){	int err=0;	int tmp;	/* step 1 */	tmp=cmd->start_src;	cmd->start_src &= TRIG_NOW;	if(!cmd->start_src || tmp!=cmd->start_src)err++;	tmp=cmd->scan_begin_src;	cmd->scan_begin_src &= TRIG_EXT;	if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;	tmp=cmd->convert_src;	cmd->convert_src &= TRIG_FOLLOW;	if(!cmd->convert_src || tmp!=cmd->convert_src)err++;	tmp=cmd->scan_end_src;	cmd->scan_end_src &= TRIG_COUNT;	if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;	tmp=cmd->stop_src;	cmd->stop_src &= TRIG_NONE;	if(!cmd->stop_src || tmp!=cmd->stop_src)err++;	if(err)return 1;	/* step 2: ignored */	if(err)return 2;	/* step 3: */	if(cmd->start_arg!=0){		cmd->start_arg = 0;		err++;	}	if(cmd->scan_begin_arg!=0){		cmd->scan_begin_arg = 0;		err++;	}	if(cmd->convert_arg!=0){		cmd->convert_arg = 0;		err++;	}	if(cmd->scan_end_arg!=1){		cmd->scan_end_arg = 1;		err++;	}	if(cmd->stop_arg!=0){		cmd->stop_arg = 0;		err++;	}	if(err)return 3;	/* step 4: ignored */	if(err)return 4;	return 0;}static int parport_intr_cmd(comedi_device *dev,comedi_subdevice *s){	devpriv->c_data |= 0x10;	outb(devpriv->c_data,dev->iobase+PARPORT_C);	devpriv->enable_irq = 1;	return 0;}static int parport_intr_cancel(comedi_device *dev,comedi_subdevice *s){	printk("parport_intr_cancel()\n");	devpriv->c_data &= ~0x10;	outb(devpriv->c_data,dev->iobase+PARPORT_C);	devpriv->enable_irq = 0;	return 0;}static void parport_interrupt(int irq,void *d,struct pt_regs *regs){	comedi_device *dev=d;	comedi_subdevice *s=dev->subdevices+3;	if(!devpriv->enable_irq){		printk("comedi_parport: bogus irq, ignored\n");		return;	}	comedi_buf_put( s->async, 0 );	s->async->events |= COMEDI_CB_EOS;		comedi_event(dev,s,s->async->events);}static int parport_attach(comedi_device *dev,comedi_devconfig *it){	int ret;	int irq;	int iobase;	comedi_subdevice *s;	iobase=it->options[0];	printk("comedi%d: parport: 0x%04x ",dev->minor,iobase);	if(check_region(iobase,PARPORT_SIZE)<0){		printk("I/O port conflict\n");		return -EIO;	}	request_region(iobase,PARPORT_SIZE,"parport (comedi)");	dev->iobase=iobase;	irq=it->options[1];	if(irq){		printk(" irq=%d",irq);		ret = comedi_request_irq(irq,parport_interrupt,0,			"comedi_parport",dev);		if(ret<0){			printk(" irq not available\n");			return -EINVAL;		}		dev->irq=irq;	}	dev->board_name="parport";	if((ret=alloc_subdevices(dev, 4))<0)		return ret;	if((ret=alloc_private(dev,sizeof(parport_private)))<0)		return ret;	s=dev->subdevices+0;	s->type=COMEDI_SUBD_DIO;	s->subdev_flags=SDF_READABLE|SDF_WRITABLE;	s->n_chan=8;	s->maxdata=1;	s->range_table=&range_digital;	s->insn_bits = parport_insn_a;	s->insn_config = parport_insn_config_a;	s=dev->subdevices+1;	s->type=COMEDI_SUBD_DI;	s->subdev_flags=SDF_READABLE;	s->n_chan=5;	s->maxdata=1;	s->range_table=&range_digital;	s->insn_bits = parport_insn_b;	s=dev->subdevices+2;	s->type=COMEDI_SUBD_DO;	s->subdev_flags=SDF_WRITABLE;	s->n_chan=4;	s->maxdata=1;	s->range_table=&range_digital;	s->insn_bits = parport_insn_c;	s=dev->subdevices+3;	dev->read_subdev=s;	if(irq){		s->type=COMEDI_SUBD_DI;		s->subdev_flags=SDF_READABLE;		s->n_chan=1;		s->maxdata=1;		s->range_table=&range_digital;		s->insn_bits = parport_intr_insn;		s->do_cmdtest = parport_intr_cmdtest;		s->do_cmd = parport_intr_cmd;		s->cancel = parport_intr_cancel;	}else{		s->type=COMEDI_SUBD_UNUSED;	}	devpriv->a_data = 0;	outb(devpriv->a_data,dev->iobase+PARPORT_A);	devpriv->c_data = 0;	outb(devpriv->c_data,dev->iobase+PARPORT_C);	printk("\n");	return 1;}static int parport_detach(comedi_device *dev){	printk("comedi%d: parport: remove\n",dev->minor);		if(dev->iobase)release_region(dev->iobase,PARPORT_SIZE);	if(dev->irq)comedi_free_irq(dev->irq,dev);	return 0;}

⌨️ 快捷键说明

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