[ARM] ecard: add helper function for setting ecard irq ops
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Thu, 10 May 2007 15:46:13 +0000 (16:46 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 11 May 2007 16:18:55 +0000 (17:18 +0100)
Rather than having every driver fiddle about setting its private
IRQ operations and data, provide a helper function to contain
this functionality in one place.

Arrange to remove the driver-private IRQ operations and data when
the device is removed from the driver, and remove the driver
private code to do this.

This fixes potential problems caused by drivers forgetting to
remove these hooks.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/ecard.c
drivers/ata/pata_icside.c
drivers/ide/arm/icside.c
drivers/net/arm/etherh.c
drivers/scsi/arm/cumana_2.c
drivers/scsi/arm/eesox.c
drivers/scsi/arm/powertec.c
include/asm-arm/ecard.h

index bdbd7da992866c78405f801d191a35e0c52adc05..65f1398723a4e86a54b522002438ab6dc8a5a775 100644 (file)
@@ -958,6 +958,14 @@ void ecard_release_resources(struct expansion_card *ec)
 }
 EXPORT_SYMBOL(ecard_release_resources);
 
+void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
+{
+       ec->irq_data = irq_data;
+       barrier();
+       ec->ops = ops;
+}
+EXPORT_SYMBOL(ecard_setirq);
+
 /*
  * Probe for an expansion card.
  *
@@ -1133,6 +1141,14 @@ static int ecard_drv_remove(struct device *dev)
        drv->remove(ec);
        ecard_release(ec);
 
+       /*
+        * Restore the default operations.  We ensure that the
+        * ops are set before we change the data.
+        */
+       ec->ops = &ecard_default_ops;
+       barrier();
+       ec->irq_data = NULL;
+
        return 0;
 }
 
index dbc8ee2adcf043445374d231de8e1b469c9a35e1..d7621a39ed0919f29275a195b4e3f361196c436f 100644 (file)
@@ -434,8 +434,8 @@ pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec)
 
        ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
        ec->irqmask = 1;
-       ec->irq_data = state;
-       ec->ops = &pata_icside_ops_arcin_v5;
+
+       ecard_setirq(ec, &pata_icside_ops_arcin_v5, state);
 
        /*
         * Be on the safe side - disable interrupts
@@ -480,8 +480,7 @@ pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec)
 
        writeb(sel, ioc_base);
 
-       ec->irq_data = state;
-       ec->ops = &pata_icside_ops_arcin_v6;
+       ecard_setirq(ec, &pata_icside_ops_arcin_v6, state);
 
        state->irq_port = easi_base;
        state->ioc_base = ioc_base;
@@ -609,8 +608,7 @@ static void pata_icside_shutdown(struct expansion_card *ec)
         * this register via that region.
         */
        local_irq_save(flags);
-       if (ec->ops)
-               ec->ops->irqdisable(ec, ec->irq);
+       ec->ops->irqdisable(ec, ec->irq);
        local_irq_restore(flags);
 
        /*
@@ -638,9 +636,6 @@ static void __devexit pata_icside_remove(struct expansion_card *ec)
         * don't NULL out the drvdata - devres/libata wants it
         * to free the ata_host structure.
         */
-       ec->ops = NULL;
-       ec->irq_data = NULL;
-
        if (state->dma != NO_DMA)
                free_dma(state->dma);
        if (state->ioc_base)
index 1fe0457243dbbcf824d8ef1f468a5ca9fe275b24..69c949ea93e3706b3c99b7098047c80b8157e0c8 100644 (file)
@@ -574,8 +574,8 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 
        ec->irqaddr  = base + ICS_ARCIN_V5_INTRSTAT;
        ec->irqmask  = 1;
-       ec->irq_data = state;
-       ec->ops      = &icside_ops_arcin_v5;
+
+       ecard_setirq(ec, &icside_ops_arcin_v5, state);
 
        /*
         * Be on the safe side - disable interrupts
@@ -630,8 +630,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 
        writeb(sel, ioc_base);
 
-       ec->irq_data      = state;
-       ec->ops           = &icside_ops_arcin_v6;
+       ecard_setirq(ec, &icside_ops_arcin_v6, state);
 
        state->irq_port   = easi_base;
        state->ioc_base   = ioc_base;
@@ -793,8 +792,6 @@ static void __devexit icside_remove(struct expansion_card *ec)
        }
 
        ecard_set_drvdata(ec, NULL);
-       ec->ops = NULL;
-       ec->irq_data = NULL;
 
        if (state->ioc_base)
                iounmap(state->ioc_base);
index 61f574aa3a991eede306c19dbb5fe4972289a889..387f1e3a4e84ede326de8539f583bac98458fca4 100644 (file)
@@ -710,8 +710,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
         * IRQ and control port handling - only for non-NIC slot cards.
         */
        if (ec->slot_no != 8) {
-               ec->ops         = &etherh_ops;
-               ec->irq_data    = eh;
+               ecard_setirq(ec, &etherh_ops, eh);
        } else {
                /*
                 * If we're in the NIC slot, make sure the IRQ is enabled
@@ -778,7 +777,6 @@ static void __devexit etherh_remove(struct expansion_card *ec)
        ecard_set_drvdata(ec, NULL);
 
        unregister_netdev(dev);
-       ec->ops = NULL;
 
        if (eh->ioc_fast)
                iounmap(eh->ioc_fast);
index 82add77ad1316714fbe7cb3b28b65f996e1ac824..f51aa3446bc7c8ff136669db8f85d639497ad884 100644 (file)
@@ -450,8 +450,8 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        ec->irqaddr     = info->base + CUMANASCSI2_STATUS;
        ec->irqmask     = STATUS_INT;
-       ec->irq_data    = info;
-       ec->ops         = &cumanascsi_2_ops;
+
+       ecard_setirq(ec, &cumanascsi_2_ops, info);
 
        ret = fas216_init(host);
        if (ret)
index ed06a8c19ad649aafcdc06c3ee5bf7fe4ca29815..cc5d513aa99af4b39e28f54cf02baadb4f6e1b43 100644 (file)
@@ -569,8 +569,8 @@ eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        ec->irqaddr     = base + EESOX_DMASTAT;
        ec->irqmask     = EESOX_STAT_INTR;
-       ec->irq_data    = info;
-       ec->ops         = &eesoxscsi_ops;
+
+       ecard_setirq(ec, &eesoxscsi_ops, info);
 
        device_create_file(&ec->dev, &dev_attr_bus_term);
 
index 159047a34997e99638f2cead22b3d634d8dadb0b..3cbd525b58c5a906deec54de925d809d45aa5abb 100644 (file)
@@ -361,8 +361,8 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        ec->irqaddr     = base + POWERTEC_INTR_STATUS;
        ec->irqmask     = POWERTEC_INTR_BIT;
-       ec->irq_data    = info;
-       ec->ops         = &powertecscsi_ops;
+
+       ecard_setirq(ec, &powertecscsi_ops, info);
 
        device_create_file(&ec->dev, &dev_attr_bus_term);
 
index 3a6d3eb2762253a64da2a5470041aee67d35302a..8f1000eac91fd499fa99068e309801f508bfd43a 100644 (file)
@@ -121,7 +121,7 @@ struct in_ecid {                    /* Packed card ID information   */
 typedef struct expansion_card ecard_t;
 typedef unsigned long *loader_t;
 
-typedef struct {                       /* Card handler routines        */
+typedef struct expansion_card_ops {    /* Card handler routines        */
        void (*irqenable)(ecard_t *ec, int irqnr);
        void (*irqdisable)(ecard_t *ec, int irqnr);
        int  (*irqpending)(ecard_t *ec);
@@ -179,6 +179,8 @@ struct expansion_card {
        u64                     dma_mask;
 };
 
+void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data);
+
 struct in_chunk_dir {
        unsigned int start_offset;
        union {