staging: comedi: refactor pcmuio driver to remove forward declarations
PATCH 1/1 staging: comedi: refactor pcmuio driver to remove forward declarations
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 <[email protected]>
Cc Ian Abbott <[email protected]>
Cc Mori Hess <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
---
drivers/staging/comedi/drivers/pcmuio.c +240 -309
@@ -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 notusedstatic 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" );