staging: comedi: refactor pcmuio driver to remove forward declarations
authorH Hartley Sweeten <hartleys@visionengravers.com>
Fri, 27 Apr 2012 22:28:57 +0000 (15:28 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Apr 2012 01:42:53 +0000 (21:42 -0400)
Refactor the switch_page and pcmuio_stop_intr functions to avoid
needing the forward declarations.

Move the module_init/module_exit routines and the associated
struct comedi_driver and other variables to the end of the source.
This is more typical of how other drivers are written and removes
the need for the forward declarations.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Cc: Mori Hess <fmhess@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/pcmuio.c

index 661ba2e..de4f486 100644 (file)
@@ -155,19 +155,6 @@ struct pcmuio_board {
        const int num_ports;
 };
 
-static const struct pcmuio_board pcmuio_boards[] = {
-       {
-        .name = "pcmuio48",
-        .num_asics = 1,
-        .num_ports = 6,
-        },
-       {
-        .name = "pcmuio96",
-        .num_asics = 2,
-        .num_ports = 12,
-        },
-};
-
 /*
  * Useful for shorthand access to the particular board structure
  */
@@ -218,262 +205,6 @@ struct pcmuio_private {
  */
 #define devpriv ((struct pcmuio_private *)dev->private)
 #define subpriv ((struct pcmuio_subdev_private *)s->private)
-/*
- * The struct 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 pcmuio_attach(struct comedi_device *dev,
-                        struct comedi_devconfig *it);
-static int pcmuio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
-       .driver_name = "pcmuio",
-       .module = THIS_MODULE,
-       .attach = pcmuio_attach,
-       .detach = pcmuio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-       /* Most drivers will support multiple types of boards by
-        * having an array of board structures.  These were defined
-        * in pcmuio_boards[] above.  Note that the element 'name'
-        * was first in the structure -- Comedi uses this fact to
-        * extract the name of the board without knowing any details
-        * about the structure except for its length.
-        * When a device is attached (by comedi_config), the name
-        * of the device is given to Comedi, and Comedi tries to
-        * match it by going through the list of board names.  If
-        * there is a match, the address of the pointer is put
-        * into dev->board_ptr and driver->attach() is called.
-        *
-        * Note that these are not necessary if you can determine
-        * the type of board in software.  ISA PnP, PCI, and PCMCIA
-        * devices are such boards.
-        */
-       .board_name = &pcmuio_boards[0].name,
-       .offset = sizeof(struct pcmuio_board),
-       .num_names = ARRAY_SIZE(pcmuio_boards),
-};
-
-static int pcmuio_dio_insn_bits(struct comedi_device *dev,
-                               struct comedi_subdevice *s,
-                               struct comedi_insn *insn, unsigned int *data);
-static int pcmuio_dio_insn_config(struct comedi_device *dev,
-                                 struct comedi_subdevice *s,
-                                 struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmuio(int irq, void *d);
-static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
-                         struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-static void init_asics(struct comedi_device *dev);     /* sets up/clears ASIC chips to defaults */
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * 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 pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-       struct comedi_subdevice *s;
-       int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
-       unsigned long iobase;
-       unsigned int irq[MAX_ASICS];
-
-       iobase = it->options[0];
-       irq[0] = it->options[1];
-       irq[1] = it->options[2];
-
-       dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
-               driver.driver_name, iobase);
-
-       dev->iobase = iobase;
-
-       if (!iobase || !request_region(iobase,
-                                      thisboard->num_asics * ASIC_IOSIZE,
-                                      driver.driver_name)) {
-               dev_err(dev->hw_dev, "I/O port conflict\n");
-               return -EIO;
-       }
-
-/*
- * Initialize dev->board_name.  Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
-       dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area.  alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
-       if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
-               dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
-               return -ENOMEM;
-       }
-
-       for (asic = 0; asic < MAX_ASICS; ++asic) {
-               devpriv->asics[asic].num = asic;
-               devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
-               devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
-                                                  this function when we
-                                                  request_irqs */
-               spin_lock_init(&devpriv->asics[asic].spinlock);
-       }
-
-       chans_left = CHANS_PER_ASIC * thisboard->num_asics;
-       n_subdevs = CALC_N_SUBDEVS(chans_left);
-       devpriv->sprivs =
-           kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
-                   GFP_KERNEL);
-       if (!devpriv->sprivs) {
-               dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
-               return -ENOMEM;
-       }
-       /*
-        * Allocate the subdevice structures.  alloc_subdevice() is a
-        * convenient macro defined in comedidev.h.
-        *
-        * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
-        * 96-channel version of the board.
-        */
-       if (alloc_subdevices(dev, n_subdevs) < 0) {
-               dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
-               return -ENOMEM;
-       }
-
-       port = 0;
-       asic = 0;
-       for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
-               int byte_no;
-
-               s = dev->subdevices + sdev_no;
-               s->private = devpriv->sprivs + sdev_no;
-               s->maxdata = 1;
-               s->range_table = &range_digital;
-               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-               s->type = COMEDI_SUBD_DIO;
-               s->insn_bits = pcmuio_dio_insn_bits;
-               s->insn_config = pcmuio_dio_insn_config;
-               s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
-               subpriv->intr.asic = -1;
-               subpriv->intr.first_chan = -1;
-               subpriv->intr.asic_chan = -1;
-               subpriv->intr.num_asic_chans = -1;
-               subpriv->intr.active = 0;
-               s->len_chanlist = 1;
-
-               /* save the ioport address for each 'port' of 8 channels in the
-                  subdevice */
-               for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
-                       if (port >= PORTS_PER_ASIC) {
-                               port = 0;
-                               ++asic;
-                               thisasic_chanct = 0;
-                       }
-                       subpriv->iobases[byte_no] =
-                           devpriv->asics[asic].iobase + port;
-
-                       if (thisasic_chanct <
-                           CHANS_PER_PORT * INTR_PORTS_PER_ASIC
-                           && subpriv->intr.asic < 0) {
-                               /* this is an interrupt subdevice, so setup the struct */
-                               subpriv->intr.asic = asic;
-                               subpriv->intr.active = 0;
-                               subpriv->intr.stop_count = 0;
-                               subpriv->intr.first_chan = byte_no * 8;
-                               subpriv->intr.asic_chan = thisasic_chanct;
-                               subpriv->intr.num_asic_chans =
-                                   s->n_chan - subpriv->intr.first_chan;
-                               dev->read_subdev = s;
-                               s->subdev_flags |= SDF_CMD_READ;
-                               s->cancel = pcmuio_cancel;
-                               s->do_cmd = pcmuio_cmd;
-                               s->do_cmdtest = pcmuio_cmdtest;
-                               s->len_chanlist = subpriv->intr.num_asic_chans;
-                       }
-                       thisasic_chanct += CHANS_PER_PORT;
-               }
-               spin_lock_init(&subpriv->intr.spinlock);
-
-               chans_left -= s->n_chan;
-
-               if (!chans_left) {
-                       asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
-                       port = 0;
-               }
-
-       }
-
-       init_asics(dev);        /* clear out all the registers, basically */
-
-       for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
-               if (irq[asic]
-                   && request_irq(irq[asic], interrupt_pcmuio,
-                                  IRQF_SHARED, thisboard->name, dev)) {
-                       int i;
-                       /* unroll the allocated irqs.. */
-                       for (i = asic - 1; i >= 0; --i) {
-                               free_irq(irq[i], dev);
-                               devpriv->asics[i].irq = irq[i] = 0;
-                       }
-                       irq[asic] = 0;
-               }
-               devpriv->asics[asic].irq = irq[asic];
-       }
-
-       dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
-                                  irqs.. */
-
-       if (irq[0]) {
-               dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
-               if (irq[1] && thisboard->num_asics == 2)
-                       dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
-       } else {
-               dev_dbg(dev->hw_dev, "(IRQ mode disabled)\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 pcmuio_detach(struct comedi_device *dev)
-{
-       int i;
-
-       dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
-               driver.driver_name);
-       if (dev->iobase)
-               release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
-
-       for (i = 0; i < MAX_ASICS; ++i) {
-               if (devpriv->asics[i].irq)
-                       free_irq(devpriv->asics[i].irq, dev);
-       }
-
-       if (devpriv && devpriv->sprivs)
-               kfree(devpriv->sprivs);
-
-       return 0;
-}
 
 /* DIO devices are slightly special.  Although it is possible to
  * implement the insn_read/insn_write interface, it is much more
@@ -621,6 +352,21 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
        return insn->n;
 }
 
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+       if (asic < 0 || asic >= thisboard->num_asics)
+               return;         /* paranoia */
+       if (page < 0 || page >= NUM_PAGES)
+               return;         /* more paranoia */
+
+       devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+       devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+       /* now write out the shadow register */
+       outb(devpriv->asics[asic].pagelock,
+            dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
+}
+
 static void init_asics(struct comedi_device *dev)
 {                              /* sets up an
                                   ASIC chip to defaults */
@@ -658,21 +404,6 @@ static void init_asics(struct comedi_device *dev)
        }
 }
 
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
-       if (asic < 0 || asic >= thisboard->num_asics)
-               return;         /* paranoia */
-       if (page < 0 || page >= NUM_PAGES)
-               return;         /* more paranoia */
-
-       devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
-       devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
-       /* now write out the shadow register */
-       outb(devpriv->asics[asic].pagelock,
-            dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
-}
-
 #ifdef notused
 static void lock_port(struct comedi_device *dev, int asic, int port)
 {
@@ -700,6 +431,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port)
 }
 #endif /* notused */
 
+static void pcmuio_stop_intr(struct comedi_device *dev,
+                            struct comedi_subdevice *s)
+{
+       int nports, firstport, asic, port;
+
+       asic = subpriv->intr.asic;
+       if (asic < 0)
+               return;         /* not an interrupt subdev */
+
+       subpriv->intr.enabled_mask = 0;
+       subpriv->intr.active = 0;
+       s->async->inttrig = 0;
+       nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
+       firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
+       switch_page(dev, asic, PAGE_ENAB);
+       for (port = firstport; port < firstport + nports; ++port) {
+               /* disable all intrs for this subdev.. */
+               outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+       }
+}
+
 static irqreturn_t interrupt_pcmuio(int irq, void *d)
 {
        int asic, got1 = 0;
@@ -852,27 +604,6 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d)
        return IRQ_HANDLED;
 }
 
-static void pcmuio_stop_intr(struct comedi_device *dev,
-                            struct comedi_subdevice *s)
-{
-       int nports, firstport, asic, port;
-
-       asic = subpriv->intr.asic;
-       if (asic < 0)
-               return;         /* not an interrupt subdev */
-
-       subpriv->intr.enabled_mask = 0;
-       subpriv->intr.active = 0;
-       s->async->inttrig = 0;
-       nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
-       firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
-       switch_page(dev, asic, PAGE_ENAB);
-       for (port = firstport; port < firstport + nports; ++port) {
-               /* disable all intrs for this subdev.. */
-               outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
-       }
-}
-
 static int pcmuio_start_intr(struct comedi_device *dev,
                             struct comedi_subdevice *s)
 {
@@ -1014,21 +745,221 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
        return comedi_pcm_cmdtest(dev, s, cmd);
 }
 
+static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+       struct comedi_subdevice *s;
+       int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
+       unsigned long iobase;
+       unsigned int irq[MAX_ASICS];
+
+       iobase = it->options[0];
+       irq[0] = it->options[1];
+       irq[1] = it->options[2];
+
+       dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
+               driver.driver_name, iobase);
+
+       dev->iobase = iobase;
+
+       if (!iobase || !request_region(iobase,
+                                      thisboard->num_asics * ASIC_IOSIZE,
+                                      driver.driver_name)) {
+               dev_err(dev->hw_dev, "I/O port conflict\n");
+               return -EIO;
+       }
+
 /*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name.  Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
+ */
+       dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area.  alloc_private() is a
+ * convenient macro defined in comedidev.h.
  */
+       if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
+               dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
+               return -ENOMEM;
+       }
+
+       for (asic = 0; asic < MAX_ASICS; ++asic) {
+               devpriv->asics[asic].num = asic;
+               devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
+               devpriv->asics[asic].irq = 0;   /* this gets actually set at the end of
+                                                  this function when we
+                                                  request_irqs */
+               spin_lock_init(&devpriv->asics[asic].spinlock);
+       }
+
+       chans_left = CHANS_PER_ASIC * thisboard->num_asics;
+       n_subdevs = CALC_N_SUBDEVS(chans_left);
+       devpriv->sprivs =
+           kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
+                   GFP_KERNEL);
+       if (!devpriv->sprivs) {
+               dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
+               return -ENOMEM;
+       }
+       /*
+        * Allocate the subdevice structures.  alloc_subdevice() is a
+        * convenient macro defined in comedidev.h.
+        *
+        * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+        * 96-channel version of the board.
+        */
+       if (alloc_subdevices(dev, n_subdevs) < 0) {
+               dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
+               return -ENOMEM;
+       }
+
+       port = 0;
+       asic = 0;
+       for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+               int byte_no;
+
+               s = dev->subdevices + sdev_no;
+               s->private = devpriv->sprivs + sdev_no;
+               s->maxdata = 1;
+               s->range_table = &range_digital;
+               s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+               s->type = COMEDI_SUBD_DIO;
+               s->insn_bits = pcmuio_dio_insn_bits;
+               s->insn_config = pcmuio_dio_insn_config;
+               s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+               subpriv->intr.asic = -1;
+               subpriv->intr.first_chan = -1;
+               subpriv->intr.asic_chan = -1;
+               subpriv->intr.num_asic_chans = -1;
+               subpriv->intr.active = 0;
+               s->len_chanlist = 1;
+
+               /* save the ioport address for each 'port' of 8 channels in the
+                  subdevice */
+               for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+                       if (port >= PORTS_PER_ASIC) {
+                               port = 0;
+                               ++asic;
+                               thisasic_chanct = 0;
+                       }
+                       subpriv->iobases[byte_no] =
+                           devpriv->asics[asic].iobase + port;
+
+                       if (thisasic_chanct <
+                           CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+                           && subpriv->intr.asic < 0) {
+                               /* this is an interrupt subdevice, so setup the struct */
+                               subpriv->intr.asic = asic;
+                               subpriv->intr.active = 0;
+                               subpriv->intr.stop_count = 0;
+                               subpriv->intr.first_chan = byte_no * 8;
+                               subpriv->intr.asic_chan = thisasic_chanct;
+                               subpriv->intr.num_asic_chans =
+                                   s->n_chan - subpriv->intr.first_chan;
+                               dev->read_subdev = s;
+                               s->subdev_flags |= SDF_CMD_READ;
+                               s->cancel = pcmuio_cancel;
+                               s->do_cmd = pcmuio_cmd;
+                               s->do_cmdtest = pcmuio_cmdtest;
+                               s->len_chanlist = subpriv->intr.num_asic_chans;
+                       }
+                       thisasic_chanct += CHANS_PER_PORT;
+               }
+               spin_lock_init(&subpriv->intr.spinlock);
+
+               chans_left -= s->n_chan;
+
+               if (!chans_left) {
+                       asic = 0;       /* reset the asic to our first asic, to do intr subdevs */
+                       port = 0;
+               }
+
+       }
+
+       init_asics(dev);        /* clear out all the registers, basically */
+
+       for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+               if (irq[asic]
+                   && request_irq(irq[asic], interrupt_pcmuio,
+                                  IRQF_SHARED, thisboard->name, dev)) {
+                       int i;
+                       /* unroll the allocated irqs.. */
+                       for (i = asic - 1; i >= 0; --i) {
+                               free_irq(irq[i], dev);
+                               devpriv->asics[i].irq = irq[i] = 0;
+                       }
+                       irq[asic] = 0;
+               }
+               devpriv->asics[asic].irq = irq[asic];
+       }
+
+       dev->irq = irq[0];      /* grr.. wish comedi dev struct supported multiple
+                                  irqs.. */
+
+       if (irq[0]) {
+               dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
+               if (irq[1] && thisboard->num_asics == 2)
+                       dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
+       } else {
+               dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
+       }
+
+
+       return 1;
+}
+
+static int pcmuio_detach(struct comedi_device *dev)
+{
+       int i;
+
+       dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
+               driver.driver_name);
+       if (dev->iobase)
+               release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
+
+       for (i = 0; i < MAX_ASICS; ++i) {
+               if (devpriv->asics[i].irq)
+                       free_irq(devpriv->asics[i].irq, dev);
+       }
+
+       if (devpriv && devpriv->sprivs)
+               kfree(devpriv->sprivs);
+
+       return 0;
+}
+
+static const struct pcmuio_board pcmuio_boards[] = {
+       {
+               .name           = "pcmuio48",
+               .num_asics      = 1,
+               .num_ports      = 6,
+       }, {
+               .name           = "pcmuio96",
+               .num_asics      = 2,
+               .num_ports      = 12,
+       },
+};
+
+static struct comedi_driver driver = {
+       .driver_name    = "pcmuio",
+       .module         = THIS_MODULE,
+       .attach         = pcmuio_attach,
+       .detach         = pcmuio_detach,
+       .board_name     = &pcmuio_boards[0].name,
+       .offset         = sizeof(struct pcmuio_board),
+       .num_names      = ARRAY_SIZE(pcmuio_boards),
+};
+
 static int __init driver_init_module(void)
 {
        return comedi_driver_register(&driver);
 }
+module_init(driver_init_module);
 
 static void __exit driver_cleanup_module(void)
 {
        comedi_driver_unregister(&driver);
 }
-
-module_init(driver_init_module);
 module_exit(driver_cleanup_module);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");