📄 comedi_parport.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 + -