root/drivers/staging/comedi/drivers/comedi_parport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parport_data_reg_insn_bits
  2. parport_data_reg_insn_config
  3. parport_status_reg_insn_bits
  4. parport_ctrl_reg_insn_bits
  5. parport_intr_insn_bits
  6. parport_intr_cmdtest
  7. parport_intr_cmd
  8. parport_intr_cancel
  9. parport_interrupt
  10. parport_attach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * comedi_parport.c
   4  * Comedi driver for standard parallel port
   5  *
   6  * For more information see:
   7  *      http://retired.beyondlogic.org/spp/parallel.htm
   8  *
   9  * COMEDI - Linux Control and Measurement Device Interface
  10  * Copyright (C) 1998,2001 David A. Schleef <ds@schleef.org>
  11  */
  12 
  13 /*
  14  * Driver: comedi_parport
  15  * Description: Standard PC parallel port
  16  * Author: ds
  17  * Status: works in immediate mode
  18  * Devices: [standard] parallel port (comedi_parport)
  19  * Updated: Tue, 30 Apr 2002 21:11:45 -0700
  20  *
  21  * A cheap and easy way to get a few more digital I/O lines. Steal
  22  * additional parallel ports from old computers or your neighbors'
  23  * computers.
  24  *
  25  * Option list:
  26  *   0: I/O port base for the parallel port.
  27  *   1: IRQ (optional)
  28  *
  29  * Parallel Port Lines:
  30  *
  31  *       pin   subdev  chan  type  name
  32  *      -----  ------  ----  ----  --------------
  33  *        1      2       0    DO   strobe
  34  *        2      0       0    DIO  data 0
  35  *        3      0       1    DIO  data 1
  36  *        4      0       2    DIO  data 2
  37  *        5      0       3    DIO  data 3
  38  *        6      0       4    DIO  data 4
  39  *        7      0       5    DIO  data 5
  40  *        8      0       6    DIO  data 6
  41  *        9      0       7    DIO  data 7
  42  *       10      1       3    DI   ack
  43  *       11      1       4    DI   busy
  44  *       12      1       2    DI   paper out
  45  *       13      1       1    DI   select in
  46  *       14      2       1    DO   auto LF
  47  *       15      1       0    DI   error
  48  *       16      2       2    DO   init
  49  *       17      2       3    DO   select printer
  50  *      18-25                      ground
  51  *
  52  * When an IRQ is configured subdevice 3 pretends to be a digital
  53  * input subdevice, but it always returns 0 when read. However, if
  54  * you run a command with scan_begin_src=TRIG_EXT, it uses pin 10
  55  * as a external trigger, which can be used to wake up tasks.
  56  */
  57 
  58 #include <linux/module.h>
  59 #include <linux/interrupt.h>
  60 
  61 #include "../comedidev.h"
  62 
  63 /*
  64  * Register map
  65  */
  66 #define PARPORT_DATA_REG        0x00
  67 #define PARPORT_STATUS_REG      0x01
  68 #define PARPORT_CTRL_REG        0x02
  69 #define PARPORT_CTRL_IRQ_ENA    BIT(4)
  70 #define PARPORT_CTRL_BIDIR_ENA  BIT(5)
  71 
  72 static int parport_data_reg_insn_bits(struct comedi_device *dev,
  73                                       struct comedi_subdevice *s,
  74                                       struct comedi_insn *insn,
  75                                       unsigned int *data)
  76 {
  77         if (comedi_dio_update_state(s, data))
  78                 outb(s->state, dev->iobase + PARPORT_DATA_REG);
  79 
  80         data[1] = inb(dev->iobase + PARPORT_DATA_REG);
  81 
  82         return insn->n;
  83 }
  84 
  85 static int parport_data_reg_insn_config(struct comedi_device *dev,
  86                                         struct comedi_subdevice *s,
  87                                         struct comedi_insn *insn,
  88                                         unsigned int *data)
  89 {
  90         unsigned int ctrl;
  91         int ret;
  92 
  93         ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
  94         if (ret)
  95                 return ret;
  96 
  97         ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
  98         if (s->io_bits)
  99                 ctrl &= ~PARPORT_CTRL_BIDIR_ENA;
 100         else
 101                 ctrl |= PARPORT_CTRL_BIDIR_ENA;
 102         outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
 103 
 104         return insn->n;
 105 }
 106 
 107 static int parport_status_reg_insn_bits(struct comedi_device *dev,
 108                                         struct comedi_subdevice *s,
 109                                         struct comedi_insn *insn,
 110                                         unsigned int *data)
 111 {
 112         data[1] = inb(dev->iobase + PARPORT_STATUS_REG) >> 3;
 113 
 114         return insn->n;
 115 }
 116 
 117 static int parport_ctrl_reg_insn_bits(struct comedi_device *dev,
 118                                       struct comedi_subdevice *s,
 119                                       struct comedi_insn *insn,
 120                                       unsigned int *data)
 121 {
 122         unsigned int ctrl;
 123 
 124         if (comedi_dio_update_state(s, data)) {
 125                 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
 126                 ctrl &= (PARPORT_CTRL_IRQ_ENA | PARPORT_CTRL_BIDIR_ENA);
 127                 ctrl |= s->state;
 128                 outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
 129         }
 130 
 131         data[1] = s->state;
 132 
 133         return insn->n;
 134 }
 135 
 136 static int parport_intr_insn_bits(struct comedi_device *dev,
 137                                   struct comedi_subdevice *s,
 138                                   struct comedi_insn *insn,
 139                                   unsigned int *data)
 140 {
 141         data[1] = 0;
 142         return insn->n;
 143 }
 144 
 145 static int parport_intr_cmdtest(struct comedi_device *dev,
 146                                 struct comedi_subdevice *s,
 147                                 struct comedi_cmd *cmd)
 148 {
 149         int err = 0;
 150 
 151         /* Step 1 : check if triggers are trivially valid */
 152 
 153         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
 154         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
 155         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
 156         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 157         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 158 
 159         if (err)
 160                 return 1;
 161 
 162         /* Step 2a : make sure trigger sources are unique */
 163         /* Step 2b : and mutually compatible */
 164 
 165         /* Step 3: check if arguments are trivially valid */
 166 
 167         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 168         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 169         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
 170         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 171                                            cmd->chanlist_len);
 172         err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 173 
 174         if (err)
 175                 return 3;
 176 
 177         /* Step 4: fix up any arguments */
 178 
 179         /* Step 5: check channel list if it exists */
 180 
 181         return 0;
 182 }
 183 
 184 static int parport_intr_cmd(struct comedi_device *dev,
 185                             struct comedi_subdevice *s)
 186 {
 187         unsigned int ctrl;
 188 
 189         ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
 190         ctrl |= PARPORT_CTRL_IRQ_ENA;
 191         outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
 192 
 193         return 0;
 194 }
 195 
 196 static int parport_intr_cancel(struct comedi_device *dev,
 197                                struct comedi_subdevice *s)
 198 {
 199         unsigned int ctrl;
 200 
 201         ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
 202         ctrl &= ~PARPORT_CTRL_IRQ_ENA;
 203         outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
 204 
 205         return 0;
 206 }
 207 
 208 static irqreturn_t parport_interrupt(int irq, void *d)
 209 {
 210         struct comedi_device *dev = d;
 211         struct comedi_subdevice *s = dev->read_subdev;
 212         unsigned int ctrl;
 213 
 214         ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
 215         if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
 216                 return IRQ_NONE;
 217 
 218         comedi_buf_write_samples(s, &s->state, 1);
 219         comedi_handle_events(dev, s);
 220 
 221         return IRQ_HANDLED;
 222 }
 223 
 224 static int parport_attach(struct comedi_device *dev,
 225                           struct comedi_devconfig *it)
 226 {
 227         struct comedi_subdevice *s;
 228         int ret;
 229 
 230         ret = comedi_request_region(dev, it->options[0], 0x03);
 231         if (ret)
 232                 return ret;
 233 
 234         if (it->options[1]) {
 235                 ret = request_irq(it->options[1], parport_interrupt, 0,
 236                                   dev->board_name, dev);
 237                 if (ret == 0)
 238                         dev->irq = it->options[1];
 239         }
 240 
 241         ret = comedi_alloc_subdevices(dev, dev->irq ? 4 : 3);
 242         if (ret)
 243                 return ret;
 244 
 245         /* Digial I/O subdevice - Parallel port DATA register */
 246         s = &dev->subdevices[0];
 247         s->type         = COMEDI_SUBD_DIO;
 248         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 249         s->n_chan       = 8;
 250         s->maxdata      = 1;
 251         s->range_table  = &range_digital;
 252         s->insn_bits    = parport_data_reg_insn_bits;
 253         s->insn_config  = parport_data_reg_insn_config;
 254 
 255         /* Digial Input subdevice - Parallel port STATUS register */
 256         s = &dev->subdevices[1];
 257         s->type         = COMEDI_SUBD_DI;
 258         s->subdev_flags = SDF_READABLE;
 259         s->n_chan       = 5;
 260         s->maxdata      = 1;
 261         s->range_table  = &range_digital;
 262         s->insn_bits    = parport_status_reg_insn_bits;
 263 
 264         /* Digial Output subdevice - Parallel port CONTROL register */
 265         s = &dev->subdevices[2];
 266         s->type         = COMEDI_SUBD_DO;
 267         s->subdev_flags = SDF_WRITABLE;
 268         s->n_chan       = 4;
 269         s->maxdata      = 1;
 270         s->range_table  = &range_digital;
 271         s->insn_bits    = parport_ctrl_reg_insn_bits;
 272 
 273         if (dev->irq) {
 274                 /* Digial Input subdevice - Interrupt support */
 275                 s = &dev->subdevices[3];
 276                 dev->read_subdev = s;
 277                 s->type         = COMEDI_SUBD_DI;
 278                 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
 279                 s->n_chan       = 1;
 280                 s->maxdata      = 1;
 281                 s->range_table  = &range_digital;
 282                 s->insn_bits    = parport_intr_insn_bits;
 283                 s->len_chanlist = 1;
 284                 s->do_cmdtest   = parport_intr_cmdtest;
 285                 s->do_cmd       = parport_intr_cmd;
 286                 s->cancel       = parport_intr_cancel;
 287         }
 288 
 289         outb(0, dev->iobase + PARPORT_DATA_REG);
 290         outb(0, dev->iobase + PARPORT_CTRL_REG);
 291 
 292         return 0;
 293 }
 294 
 295 static struct comedi_driver parport_driver = {
 296         .driver_name    = "comedi_parport",
 297         .module         = THIS_MODULE,
 298         .attach         = parport_attach,
 299         .detach         = comedi_legacy_detach,
 300 };
 301 module_comedi_driver(parport_driver);
 302 
 303 MODULE_AUTHOR("Comedi http://www.comedi.org");
 304 MODULE_DESCRIPTION("Comedi: Standard parallel port driver");
 305 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */