tricky one: hisax sections
[safe/jmp/linux-2.6] / drivers / isdn / hisax / config.c
index 29e98f7..ded9d0b 100644 (file)
@@ -361,11 +361,11 @@ module_param_array(io1, int, NULL, 0);
 
 int nrcards;
 
-extern char *l1_revision;
-extern char *l2_revision;
-extern char *l3_revision;
-extern char *lli_revision;
-extern char *tei_revision;
+extern const char *l1_revision;
+extern const char *l2_revision;
+extern const char *l3_revision;
+extern const char *lli_revision;
+extern const char *tei_revision;
 
 char *HiSax_getrev(const char *revision)
 {
@@ -549,10 +549,6 @@ extern int setup_isurf(struct IsdnCard *card);
 extern int setup_saphir(struct IsdnCard *card);
 #endif
 
-#if CARD_TESTEMU
-extern int setup_testemu(struct IsdnCard *card);
-#endif
-
 #if CARD_BKM_A4T
 extern int setup_bkm_a4t(struct IsdnCard *card);
 #endif
@@ -851,95 +847,10 @@ static int init_card(struct IsdnCardState *cs)
        return 3;
 }
 
-static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
+static int __devinit hisax_cs_setup_card(struct IsdnCard *card)
 {
-       int ret = 0;
-       struct IsdnCard *card = cards + cardnr;
-       struct IsdnCardState *cs;
-
-       cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
-       if (!cs) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for IsdnCardState(card %d)\n",
-                      cardnr + 1);
-               goto out;
-       }
-       card->cs = cs;
-       spin_lock_init(&cs->statlock);
-       spin_lock_init(&cs->lock);
-       cs->chanlimit = 2;      /* maximum B-channel number */
-       cs->logecho = 0;        /* No echo logging */
-       cs->cardnr = cardnr;
-       cs->debug = L1_DEB_WARN;
-       cs->HW_Flags = 0;
-       cs->busy_flag = busy_flag;
-       cs->irq_flags = I4L_IRQ_FLAG;
-#if TEI_PER_CARD
-       if (card->protocol == ISDN_PTYPE_NI1)
-               test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
-       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
-       cs->protocol = card->protocol;
-
-       if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
-               printk(KERN_WARNING
-                      "HiSax: Card Type %d out of range\n", card->typ);
-               goto outf_cs;
-       }
-       if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
-               goto outf_cs;
-       }
-       if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for status_buf(card %d)\n",
-                      cardnr + 1);
-               goto outf_dlog;
-       }
-       cs->stlist = NULL;
-       cs->status_read = cs->status_buf;
-       cs->status_write = cs->status_buf;
-       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
-       cs->typ = card->typ;
-#ifdef MODULE
-       cs->iif.owner = lockowner;
-#endif
-       strcpy(cs->iif.id, id);
-       cs->iif.channels = 2;
-       cs->iif.maxbufsize = MAX_DATA_SIZE;
-       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
-       cs->iif.features =
-               ISDN_FEATURE_L2_X75I |
-               ISDN_FEATURE_L2_HDLC |
-               ISDN_FEATURE_L2_HDLC_56K |
-               ISDN_FEATURE_L2_TRANS |
-               ISDN_FEATURE_L3_TRANS |
-#ifdef CONFIG_HISAX_1TR6
-               ISDN_FEATURE_P_1TR6 |
-#endif
-#ifdef CONFIG_HISAX_EURO
-               ISDN_FEATURE_P_EURO |
-#endif
-#ifdef CONFIG_HISAX_NI1
-               ISDN_FEATURE_P_NI1 |
-#endif
-               0;
+       int ret;
 
-       cs->iif.command = HiSax_command;
-       cs->iif.writecmd = NULL;
-       cs->iif.writebuf_skb = HiSax_writebuf_skb;
-       cs->iif.readstat = HiSax_readstatus;
-       register_isdn(&cs->iif);
-       cs->myid = cs->iif.channels;
-       printk(KERN_INFO
-              "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
-              (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
-              (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
-              (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
-              (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
-              "NONE", cs->iif.id, cs->myid);
        switch (card->typ) {
 #if CARD_TELES0
        case ISDN_CTYPE_16_0:
@@ -1061,11 +972,6 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
                ret = setup_saphir(card);
                break;
 #endif
-#if CARD_TESTEMU
-       case ISDN_CTYPE_TESTEMU:
-               ret = setup_testemu(card);
-               break;
-#endif
 #if    CARD_BKM_A4T
        case ISDN_CTYPE_BKM_A4T:
                ret = setup_bkm_a4t(card);
@@ -1103,13 +1009,115 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
                printk(KERN_WARNING
                       "HiSax: Support for %s Card not selected\n",
                       CardType[card->typ]);
-               ll_unload(cs);
+               ret = 0;
+               break;
+       }
+
+       return ret;
+}
+
+static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card,
+                       struct IsdnCardState **cs_out, int *busy_flag,
+                       struct module *lockowner)
+{
+       struct IsdnCardState *cs;
+
+       *cs_out = NULL;
+
+       cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+       if (!cs) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for IsdnCardState(card %d)\n",
+                      cardnr + 1);
+               goto out;
+       }
+       card->cs = cs;
+       spin_lock_init(&cs->statlock);
+       spin_lock_init(&cs->lock);
+       cs->chanlimit = 2;      /* maximum B-channel number */
+       cs->logecho = 0;        /* No echo logging */
+       cs->cardnr = cardnr;
+       cs->debug = L1_DEB_WARN;
+       cs->HW_Flags = 0;
+       cs->busy_flag = busy_flag;
+       cs->irq_flags = I4L_IRQ_FLAG;
+#if TEI_PER_CARD
+       if (card->protocol == ISDN_PTYPE_NI1)
+               test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#else
+       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+       cs->protocol = card->protocol;
+
+       if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
+               printk(KERN_WARNING
+                      "HiSax: Card Type %d out of range\n", card->typ);
                goto outf_cs;
        }
-       if (!ret) {
-               ll_unload(cs);
+       if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
                goto outf_cs;
        }
+       if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for status_buf(card %d)\n",
+                      cardnr + 1);
+               goto outf_dlog;
+       }
+       cs->stlist = NULL;
+       cs->status_read = cs->status_buf;
+       cs->status_write = cs->status_buf;
+       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+       cs->typ = card->typ;
+#ifdef MODULE
+       cs->iif.owner = lockowner;
+#endif
+       strcpy(cs->iif.id, id);
+       cs->iif.channels = 2;
+       cs->iif.maxbufsize = MAX_DATA_SIZE;
+       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+       cs->iif.features =
+               ISDN_FEATURE_L2_X75I |
+               ISDN_FEATURE_L2_HDLC |
+               ISDN_FEATURE_L2_HDLC_56K |
+               ISDN_FEATURE_L2_TRANS |
+               ISDN_FEATURE_L3_TRANS |
+#ifdef CONFIG_HISAX_1TR6
+               ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef CONFIG_HISAX_EURO
+               ISDN_FEATURE_P_EURO |
+#endif
+#ifdef CONFIG_HISAX_NI1
+               ISDN_FEATURE_P_NI1 |
+#endif
+               0;
+
+       cs->iif.command = HiSax_command;
+       cs->iif.writecmd = NULL;
+       cs->iif.writebuf_skb = HiSax_writebuf_skb;
+       cs->iif.readstat = HiSax_readstatus;
+       register_isdn(&cs->iif);
+       cs->myid = cs->iif.channels;
+
+       *cs_out = cs;
+       return 1;       /* success */
+
+outf_dlog:
+       kfree(cs->dlog);
+outf_cs:
+       kfree(cs);
+       card->cs = NULL;
+out:
+       return 0;       /* error */
+}
+
+static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
+                         struct IsdnCardState *cs)
+{
+       int ret;
+
        if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
                printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
                ll_unload(cs);
@@ -1138,25 +1146,58 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
        }
        if (ret) {
                closecard(cardnr);
-               ret = 0;
                goto outf_cs;
        }
        init_tei(cs, cs->protocol);
        ret = CallcNewChan(cs);
        if (ret) {
                closecard(cardnr);
-               ret = 0;
                goto outf_cs;
        }
        /* ISAR needs firmware download first */
        if (!test_bit(HW_ISAR, &cs->HW_Flags))
                ll_run(cs, 0);
 
-       ret = 1;
+       return 1;
+
+outf_cs:
+       kfree(cs);
+       card->cs = NULL;
+       return 0;
+}
+
+/* Used from an exported function but calls __devinit functions.
+ * Tell modpost not to warn (__ref)
+ */
+static int __ref checkcard(int cardnr, char *id, int *busy_flag,
+                          struct module *lockowner,
+                          hisax_setup_func_t card_setup)
+{
+       int ret;
+       struct IsdnCard *card = cards + cardnr;
+       struct IsdnCardState *cs;
+
+       ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner);
+       if (!ret)
+               return 0;
+
+       printk(KERN_INFO
+              "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+              (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+              (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+              (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+              (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+              "NONE", cs->iif.id, cs->myid);
+
+       ret = card_setup(card);
+       if (!ret) {
+               ll_unload(cs);
+               goto outf_cs;
+       }
+
+       ret = hisax_cs_setup(cardnr, card, cs);
        goto out;
 
- outf_dlog:
-       kfree(cs->dlog);
  outf_cs:
        kfree(cs);
        card->cs = NULL;
@@ -1172,7 +1213,7 @@ static void HiSax_shiftcards(int idx)
                memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-static int HiSax_inithardware(int *busy_flag)
+static int __init HiSax_inithardware(int *busy_flag)
 {
        int foundcards = 0;
        int i = 0;
@@ -1202,7 +1243,8 @@ static int HiSax_inithardware(int *busy_flag)
                        else
                                sprintf(ids, "%s%d", id, i);
                }
-               if (checkcard(i, ids, busy_flag, THIS_MODULE)) {
+               if (checkcard(i, ids, busy_flag, THIS_MODULE,
+                             hisax_cs_setup_card)) {
                        foundcards++;
                        i++;
                } else {
@@ -1500,7 +1542,9 @@ static void __exit HiSax_exit(void)
        printk(KERN_INFO "HiSax module removed\n");
 }
 
-int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+#ifdef CONFIG_HOTPLUG
+
+int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
 {
        u_char ids[16];
        int ret = -1;
@@ -1510,7 +1554,8 @@ int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
                sprintf(ids, "HiSax%d", nrcards);
        else
                sprintf(ids, "HiSax");
-       if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE))
+       if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE,
+                      hisax_cs_setup_card))
                goto error;
 
        ret = nrcards;
@@ -1520,6 +1565,8 @@ error:
 }
 
 EXPORT_SYMBOL(hisax_init_pcmcia);
+#endif
+
 EXPORT_SYMBOL(HiSax_closecard);
 
 #include "hisax_if.h"
@@ -1537,6 +1584,11 @@ static void hisax_bc_close(struct BCState *bcs);
 static void hisax_bh(struct work_struct *work);
 static void EChannel_proc_rcv(struct hisax_d_if *d_if);
 
+static int hisax_setup_card_dynamic(struct IsdnCard *card)
+{
+       return 2;
+}
+
 int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
                   char *name, int protocol)
 {
@@ -1556,11 +1608,12 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
        cards[i].protocol = protocol;
        sprintf(id, "%s%d", name, i);
        nrcards++;
-       retval = checkcard(i, id, NULL, hisax_d_if->owner);
+       retval = checkcard(i, id, NULL, hisax_d_if->owner,
+                               hisax_setup_card_dynamic);
        if (retval == 0) { // yuck
                cards[i].typ = 0;
                nrcards--;
-               return retval;
+               return -EINVAL;
        }
        cs = cards[i].cs;
        hisax_d_if->cs = cs;