diff options
| -rw-r--r-- | drivers/isdn/hardware/mISDN/hfcmulti.c | 6 | ||||
| -rw-r--r-- | drivers/isdn/hardware/mISDN/hfcpci.c | 100 | ||||
| -rw-r--r-- | drivers/isdn/mISDN/core.c | 271 | ||||
| -rw-r--r-- | drivers/isdn/mISDN/l1oip_core.c | 3 | ||||
| -rw-r--r-- | include/linux/mISDNif.h | 8 |
5 files changed, 273 insertions, 115 deletions
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index cd3f3994b7f8..97f4708b3879 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
| @@ -4718,7 +4718,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) | |||
| 4718 | } else | 4718 | } else |
| 4719 | hc->chan[hc->dslot].jitter = 2; /* default */ | 4719 | hc->chan[hc->dslot].jitter = 2; /* default */ |
| 4720 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); | 4720 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); |
| 4721 | ret = mISDN_register_device(&dch->dev, name); | 4721 | ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); |
| 4722 | if (ret) | 4722 | if (ret) |
| 4723 | goto free_chan; | 4723 | goto free_chan; |
| 4724 | hc->created[0] = 1; | 4724 | hc->created[0] = 1; |
| @@ -4826,9 +4826,9 @@ init_multi_port(struct hfc_multi *hc, int pt) | |||
| 4826 | test_and_set_bit(HFC_CFG_DIS_ECHANNEL, | 4826 | test_and_set_bit(HFC_CFG_DIS_ECHANNEL, |
| 4827 | &hc->chan[i + 2].cfg); | 4827 | &hc->chan[i + 2].cfg); |
| 4828 | } | 4828 | } |
| 4829 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d", | 4829 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", |
| 4830 | hc->type, HFC_cnt + 1, pt + 1); | 4830 | hc->type, HFC_cnt + 1, pt + 1); |
| 4831 | ret = mISDN_register_device(&dch->dev, name); | 4831 | ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); |
| 4832 | if (ret) | 4832 | if (ret) |
| 4833 | goto free_chan; | 4833 | goto free_chan; |
| 4834 | hc->created[pt] = 1; | 4834 | hc->created[pt] = 1; |
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd5d26c9909f..8df12bf02af3 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c | |||
| @@ -64,9 +64,6 @@ MODULE_LICENSE("GPL"); | |||
| 64 | module_param(debug, uint, 0); | 64 | module_param(debug, uint, 0); |
| 65 | module_param(poll, uint, S_IRUGO | S_IWUSR); | 65 | module_param(poll, uint, S_IRUGO | S_IWUSR); |
| 66 | 66 | ||
| 67 | static LIST_HEAD(HFClist); | ||
| 68 | static DEFINE_RWLOCK(HFClock); | ||
| 69 | |||
| 70 | enum { | 67 | enum { |
| 71 | HFC_CCD_2BD0, | 68 | HFC_CCD_2BD0, |
| 72 | HFC_CCD_B000, | 69 | HFC_CCD_B000, |
| @@ -136,7 +133,6 @@ struct hfcPCI_hw { | |||
| 136 | 133 | ||
| 137 | 134 | ||
| 138 | struct hfc_pci { | 135 | struct hfc_pci { |
| 139 | struct list_head list; | ||
| 140 | u_char subtype; | 136 | u_char subtype; |
| 141 | u_char chanlimit; | 137 | u_char chanlimit; |
| 142 | u_char initdone; | 138 | u_char initdone; |
| @@ -1227,41 +1223,6 @@ hfcpci_int(int intno, void *dev_id) | |||
| 1227 | return IRQ_HANDLED; | 1223 | return IRQ_HANDLED; |
| 1228 | } | 1224 | } |
| 1229 | 1225 | ||
| 1230 | static void | ||
| 1231 | hfcpci_softirq(void *arg) | ||
| 1232 | { | ||
| 1233 | u_long flags; | ||
| 1234 | struct bchannel *bch; | ||
| 1235 | struct hfc_pci *hc; | ||
| 1236 | |||
| 1237 | write_lock_irqsave(&HFClock, flags); | ||
| 1238 | list_for_each_entry(hc, &HFClist, list) { | ||
| 1239 | if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { | ||
| 1240 | spin_lock(&hc->lock); | ||
| 1241 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
| 1242 | if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ | ||
| 1243 | main_rec_hfcpci(bch); | ||
| 1244 | tx_birq(bch); | ||
| 1245 | } | ||
| 1246 | bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); | ||
| 1247 | if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ | ||
| 1248 | main_rec_hfcpci(bch); | ||
| 1249 | tx_birq(bch); | ||
| 1250 | } | ||
| 1251 | spin_unlock(&hc->lock); | ||
| 1252 | } | ||
| 1253 | } | ||
| 1254 | write_unlock_irqrestore(&HFClock, flags); | ||
| 1255 | |||
| 1256 | /* if next event would be in the past ... */ | ||
| 1257 | if ((s32)(hfc_jiffies + tics - jiffies) <= 0) | ||
| 1258 | hfc_jiffies = jiffies + 1; | ||
| 1259 | else | ||
| 1260 | hfc_jiffies += tics; | ||
| 1261 | hfc_tl.expires = hfc_jiffies; | ||
| 1262 | add_timer(&hfc_tl); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | /* | 1226 | /* |
| 1266 | * timer callback for D-chan busy resolution. Currently no function | 1227 | * timer callback for D-chan busy resolution. Currently no function |
| 1267 | */ | 1228 | */ |
| @@ -2131,7 +2092,6 @@ release_card(struct hfc_pci *hc) { | |||
| 2131 | mISDN_freebchannel(&hc->bch[1]); | 2092 | mISDN_freebchannel(&hc->bch[1]); |
| 2132 | mISDN_freebchannel(&hc->bch[0]); | 2093 | mISDN_freebchannel(&hc->bch[0]); |
| 2133 | mISDN_freedchannel(&hc->dch); | 2094 | mISDN_freedchannel(&hc->dch); |
| 2134 | list_del(&hc->list); | ||
| 2135 | pci_set_drvdata(hc->pdev, NULL); | 2095 | pci_set_drvdata(hc->pdev, NULL); |
| 2136 | kfree(hc); | 2096 | kfree(hc); |
| 2137 | } | 2097 | } |
| @@ -2141,7 +2101,6 @@ setup_card(struct hfc_pci *card) | |||
| 2141 | { | 2101 | { |
| 2142 | int err = -EINVAL; | 2102 | int err = -EINVAL; |
| 2143 | u_int i; | 2103 | u_int i; |
| 2144 | u_long flags; | ||
| 2145 | char name[MISDN_MAX_IDLEN]; | 2104 | char name[MISDN_MAX_IDLEN]; |
| 2146 | 2105 | ||
| 2147 | card->dch.debug = debug; | 2106 | card->dch.debug = debug; |
| @@ -2169,13 +2128,10 @@ setup_card(struct hfc_pci *card) | |||
| 2169 | if (err) | 2128 | if (err) |
| 2170 | goto error; | 2129 | goto error; |
| 2171 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); | 2130 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); |
| 2172 | err = mISDN_register_device(&card->dch.dev, name); | 2131 | err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); |
| 2173 | if (err) | 2132 | if (err) |
| 2174 | goto error; | 2133 | goto error; |
| 2175 | HFC_cnt++; | 2134 | HFC_cnt++; |
| 2176 | write_lock_irqsave(&HFClock, flags); | ||
| 2177 | list_add_tail(&card->list, &HFClist); | ||
| 2178 | write_unlock_irqrestore(&HFClock, flags); | ||
| 2179 | printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); | 2135 | printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); |
| 2180 | return 0; | 2136 | return 0; |
| 2181 | error: | 2137 | error: |
| @@ -2311,15 +2267,12 @@ static void __devexit | |||
| 2311 | hfc_remove_pci(struct pci_dev *pdev) | 2267 | hfc_remove_pci(struct pci_dev *pdev) |
| 2312 | { | 2268 | { |
| 2313 | struct hfc_pci *card = pci_get_drvdata(pdev); | 2269 | struct hfc_pci *card = pci_get_drvdata(pdev); |
| 2314 | u_long flags; | ||
| 2315 | 2270 | ||
| 2316 | if (card) { | 2271 | if (card) |
| 2317 | write_lock_irqsave(&HFClock, flags); | ||
| 2318 | release_card(card); | 2272 | release_card(card); |
| 2319 | write_unlock_irqrestore(&HFClock, flags); | 2273 | else |
| 2320 | } else | ||
| 2321 | if (debug) | 2274 | if (debug) |
| 2322 | printk(KERN_WARNING "%s: drvdata allready removed\n", | 2275 | printk(KERN_WARNING "%s: drvdata already removed\n", |
| 2323 | __func__); | 2276 | __func__); |
| 2324 | } | 2277 | } |
| 2325 | 2278 | ||
| @@ -2331,6 +2284,46 @@ static struct pci_driver hfc_driver = { | |||
| 2331 | .id_table = hfc_ids, | 2284 | .id_table = hfc_ids, |
| 2332 | }; | 2285 | }; |
| 2333 | 2286 | ||
| 2287 | static int | ||
| 2288 | _hfcpci_softirq(struct device *dev, void *arg) | ||
| 2289 | { | ||
| 2290 | struct hfc_pci *hc = dev_get_drvdata(dev); | ||
| 2291 | struct bchannel *bch; | ||
| 2292 | if (hc == NULL) | ||
| 2293 | return 0; | ||
| 2294 | |||
| 2295 | if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { | ||
| 2296 | spin_lock(&hc->lock); | ||
| 2297 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
| 2298 | if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ | ||
| 2299 | main_rec_hfcpci(bch); | ||
| 2300 | tx_birq(bch); | ||
| 2301 | } | ||
| 2302 | bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); | ||
| 2303 | if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ | ||
| 2304 | main_rec_hfcpci(bch); | ||
| 2305 | tx_birq(bch); | ||
| 2306 | } | ||
| 2307 | spin_unlock(&hc->lock); | ||
| 2308 | } | ||
| 2309 | return 0; | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | static void | ||
| 2313 | hfcpci_softirq(void *arg) | ||
| 2314 | { | ||
| 2315 | (void) driver_for_each_device(&hfc_driver.driver, NULL, arg, | ||
| 2316 | _hfcpci_softirq); | ||
| 2317 | |||
| 2318 | /* if next event would be in the past ... */ | ||
| 2319 | if ((s32)(hfc_jiffies + tics - jiffies) <= 0) | ||
| 2320 | hfc_jiffies = jiffies + 1; | ||
| 2321 | else | ||
| 2322 | hfc_jiffies += tics; | ||
| 2323 | hfc_tl.expires = hfc_jiffies; | ||
| 2324 | add_timer(&hfc_tl); | ||
| 2325 | } | ||
| 2326 | |||
| 2334 | static int __init | 2327 | static int __init |
| 2335 | HFC_init(void) | 2328 | HFC_init(void) |
| 2336 | { | 2329 | { |
| @@ -2375,14 +2368,9 @@ HFC_init(void) | |||
| 2375 | static void __exit | 2368 | static void __exit |
| 2376 | HFC_cleanup(void) | 2369 | HFC_cleanup(void) |
| 2377 | { | 2370 | { |
| 2378 | struct hfc_pci *card, *next; | ||
| 2379 | |||
| 2380 | if (timer_pending(&hfc_tl)) | 2371 | if (timer_pending(&hfc_tl)) |
| 2381 | del_timer(&hfc_tl); | 2372 | del_timer(&hfc_tl); |
| 2382 | 2373 | ||
| 2383 | list_for_each_entry_safe(card, next, &HFClist, list) { | ||
| 2384 | release_card(card); | ||
| 2385 | } | ||
| 2386 | pci_unregister_driver(&hfc_driver); | 2374 | pci_unregister_driver(&hfc_driver); |
| 2387 | } | 2375 | } |
| 2388 | 2376 | ||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 9116f54def2c..9426c9827e47 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c | |||
| @@ -25,39 +25,183 @@ MODULE_AUTHOR("Karsten Keil"); | |||
| 25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
| 26 | module_param(debug, uint, S_IRUGO | S_IWUSR); | 26 | module_param(debug, uint, S_IRUGO | S_IWUSR); |
| 27 | 27 | ||
| 28 | static LIST_HEAD(devices); | ||
| 29 | static DEFINE_RWLOCK(device_lock); | ||
| 30 | static u64 device_ids; | 28 | static u64 device_ids; |
| 31 | #define MAX_DEVICE_ID 63 | 29 | #define MAX_DEVICE_ID 63 |
| 32 | 30 | ||
| 33 | static LIST_HEAD(Bprotocols); | 31 | static LIST_HEAD(Bprotocols); |
| 34 | static DEFINE_RWLOCK(bp_lock); | 32 | static DEFINE_RWLOCK(bp_lock); |
| 35 | 33 | ||
| 34 | static void mISDN_dev_release(struct device *dev) | ||
| 35 | { | ||
| 36 | /* nothing to do: the device is part of its parent's data structure */ | ||
| 37 | } | ||
| 38 | |||
| 39 | static ssize_t _show_id(struct device *dev, | ||
| 40 | struct device_attribute *attr, char *buf) | ||
| 41 | { | ||
| 42 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 43 | |||
| 44 | if (!mdev) | ||
| 45 | return -ENODEV; | ||
| 46 | return sprintf(buf, "%d\n", mdev->id); | ||
| 47 | } | ||
| 48 | |||
| 49 | static ssize_t _show_nrbchan(struct device *dev, | ||
| 50 | struct device_attribute *attr, char *buf) | ||
| 51 | { | ||
| 52 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 53 | |||
| 54 | if (!mdev) | ||
| 55 | return -ENODEV; | ||
| 56 | return sprintf(buf, "%d\n", mdev->nrbchan); | ||
| 57 | } | ||
| 58 | |||
| 59 | static ssize_t _show_d_protocols(struct device *dev, | ||
| 60 | struct device_attribute *attr, char *buf) | ||
| 61 | { | ||
| 62 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 63 | |||
| 64 | if (!mdev) | ||
| 65 | return -ENODEV; | ||
| 66 | return sprintf(buf, "%d\n", mdev->Dprotocols); | ||
| 67 | } | ||
| 68 | |||
| 69 | static ssize_t _show_b_protocols(struct device *dev, | ||
| 70 | struct device_attribute *attr, char *buf) | ||
| 71 | { | ||
| 72 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 73 | |||
| 74 | if (!mdev) | ||
| 75 | return -ENODEV; | ||
| 76 | return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols()); | ||
| 77 | } | ||
| 78 | |||
| 79 | static ssize_t _show_protocol(struct device *dev, | ||
| 80 | struct device_attribute *attr, char *buf) | ||
| 81 | { | ||
| 82 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 83 | |||
| 84 | if (!mdev) | ||
| 85 | return -ENODEV; | ||
| 86 | return sprintf(buf, "%d\n", mdev->D.protocol); | ||
| 87 | } | ||
| 88 | |||
| 89 | static ssize_t _show_name(struct device *dev, | ||
| 90 | struct device_attribute *attr, char *buf) | ||
| 91 | { | ||
| 92 | strcpy(buf, dev_name(dev)); | ||
| 93 | return strlen(buf); | ||
| 94 | } | ||
| 95 | |||
| 96 | #if 0 /* hangs */ | ||
| 97 | static ssize_t _set_name(struct device *dev, struct device_attribute *attr, | ||
| 98 | const char *buf, size_t count) | ||
| 99 | { | ||
| 100 | int err = 0; | ||
| 101 | char *out = kmalloc(count + 1, GFP_KERNEL); | ||
| 102 | |||
| 103 | if (!out) | ||
| 104 | return -ENOMEM; | ||
| 105 | |||
| 106 | memcpy(out, buf, count); | ||
| 107 | if (count && out[count - 1] == '\n') | ||
| 108 | out[--count] = 0; | ||
| 109 | if (count) | ||
| 110 | err = device_rename(dev, out); | ||
| 111 | kfree(out); | ||
| 112 | |||
| 113 | return (err < 0) ? err : count; | ||
| 114 | } | ||
| 115 | #endif | ||
| 116 | |||
| 117 | static ssize_t _show_channelmap(struct device *dev, | ||
| 118 | struct device_attribute *attr, char *buf) | ||
| 119 | { | ||
| 120 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 121 | char *bp = buf; | ||
| 122 | int i; | ||
| 123 | |||
| 124 | for (i = 0; i <= mdev->nrbchan; i++) | ||
| 125 | *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0'; | ||
| 126 | |||
| 127 | return bp - buf; | ||
| 128 | } | ||
| 129 | |||
| 130 | static struct device_attribute mISDN_dev_attrs[] = { | ||
| 131 | __ATTR(id, S_IRUGO, _show_id, NULL), | ||
| 132 | __ATTR(d_protocols, S_IRUGO, _show_d_protocols, NULL), | ||
| 133 | __ATTR(b_protocols, S_IRUGO, _show_b_protocols, NULL), | ||
| 134 | __ATTR(protocol, S_IRUGO, _show_protocol, NULL), | ||
| 135 | __ATTR(channelmap, S_IRUGO, _show_channelmap, NULL), | ||
| 136 | __ATTR(nrbchan, S_IRUGO, _show_nrbchan, NULL), | ||
| 137 | __ATTR(name, S_IRUGO, _show_name, NULL), | ||
| 138 | /* __ATTR(name, S_IRUGO|S_IWUSR, _show_name, _set_name), */ | ||
| 139 | {} | ||
| 140 | }; | ||
| 141 | |||
| 142 | #ifdef CONFIG_HOTPLUG | ||
| 143 | static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 144 | { | ||
| 145 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 146 | |||
| 147 | if (!mdev) | ||
| 148 | return 0; | ||
| 149 | |||
| 150 | if (add_uevent_var(env, "nchans=%d", mdev->nrbchan)) | ||
| 151 | return -ENOMEM; | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | #endif | ||
| 156 | |||
| 157 | static void mISDN_class_release(struct class *cls) | ||
| 158 | { | ||
| 159 | /* do nothing, it's static */ | ||
| 160 | } | ||
| 161 | |||
| 162 | static struct class mISDN_class = { | ||
| 163 | .name = "mISDN", | ||
| 164 | .owner = THIS_MODULE, | ||
| 165 | #ifdef CONFIG_HOTPLUG | ||
| 166 | .dev_uevent = mISDN_uevent, | ||
| 167 | #endif | ||
| 168 | .dev_attrs = mISDN_dev_attrs, | ||
| 169 | .dev_release = mISDN_dev_release, | ||
| 170 | .class_release = mISDN_class_release, | ||
| 171 | }; | ||
| 172 | |||
| 173 | static int | ||
| 174 | _get_mdevice(struct device *dev, void *id) | ||
| 175 | { | ||
| 176 | struct mISDNdevice *mdev = dev_to_mISDN(dev); | ||
| 177 | |||
| 178 | if (!mdev) | ||
| 179 | return 0; | ||
| 180 | if (mdev->id != *(u_int *)id) | ||
| 181 | return 0; | ||
| 182 | return 1; | ||
| 183 | } | ||
| 184 | |||
| 36 | struct mISDNdevice | 185 | struct mISDNdevice |
| 37 | *get_mdevice(u_int id) | 186 | *get_mdevice(u_int id) |
| 38 | { | 187 | { |
| 39 | struct mISDNdevice *dev; | 188 | return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id, |
| 189 | _get_mdevice)); | ||
| 190 | } | ||
| 40 | 191 | ||
| 41 | read_lock(&device_lock); | 192 | static int |
| 42 | list_for_each_entry(dev, &devices, D.list) | 193 | _get_mdevice_count(struct device *dev, void *cnt) |
| 43 | if (dev->id == id) { | 194 | { |
| 44 | read_unlock(&device_lock); | 195 | *(int *)cnt += 1; |
| 45 | return dev; | 196 | return 0; |
| 46 | } | ||
| 47 | read_unlock(&device_lock); | ||
| 48 | return NULL; | ||
| 49 | } | 197 | } |
| 50 | 198 | ||
| 51 | int | 199 | int |
| 52 | get_mdevice_count(void) | 200 | get_mdevice_count(void) |
| 53 | { | 201 | { |
| 54 | struct mISDNdevice *dev; | 202 | int cnt = 0; |
| 55 | int cnt = 0; | ||
| 56 | 203 | ||
| 57 | read_lock(&device_lock); | 204 | class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count); |
| 58 | list_for_each_entry(dev, &devices, D.list) | ||
| 59 | cnt++; | ||
| 60 | read_unlock(&device_lock); | ||
| 61 | return cnt; | 205 | return cnt; |
| 62 | } | 206 | } |
| 63 | 207 | ||
| @@ -68,19 +212,24 @@ get_free_devid(void) | |||
| 68 | 212 | ||
| 69 | for (i = 0; i <= MAX_DEVICE_ID; i++) | 213 | for (i = 0; i <= MAX_DEVICE_ID; i++) |
| 70 | if (!test_and_set_bit(i, (u_long *)&device_ids)) | 214 | if (!test_and_set_bit(i, (u_long *)&device_ids)) |
| 71 | return i; | 215 | break; |
| 72 | return -1; | 216 | if (i > MAX_DEVICE_ID) |
| 217 | return -1; | ||
| 218 | return i; | ||
| 73 | } | 219 | } |
| 74 | 220 | ||
| 75 | int | 221 | int |
| 76 | mISDN_register_device(struct mISDNdevice *dev, char *name) | 222 | mISDN_register_device(struct mISDNdevice *dev, |
| 223 | struct device *parent, char *name) | ||
| 77 | { | 224 | { |
| 78 | u_long flags; | ||
| 79 | int err; | 225 | int err; |
| 80 | 226 | ||
| 81 | dev->id = get_free_devid(); | 227 | dev->id = get_free_devid(); |
| 228 | err = -EBUSY; | ||
| 82 | if (dev->id < 0) | 229 | if (dev->id < 0) |
| 83 | return -EBUSY; | 230 | goto error1; |
| 231 | |||
| 232 | device_initialize(&dev->dev); | ||
| 84 | if (name && name[0]) | 233 | if (name && name[0]) |
| 85 | dev_set_name(&dev->dev, "%s", name); | 234 | dev_set_name(&dev->dev, "%s", name); |
| 86 | else | 235 | else |
| @@ -90,26 +239,39 @@ mISDN_register_device(struct mISDNdevice *dev, char *name) | |||
| 90 | dev_name(&dev->dev), dev->id); | 239 | dev_name(&dev->dev), dev->id); |
| 91 | err = create_stack(dev); | 240 | err = create_stack(dev); |
| 92 | if (err) | 241 | if (err) |
| 93 | return err; | 242 | goto error1; |
| 94 | write_lock_irqsave(&device_lock, flags); | 243 | |
| 95 | list_add_tail(&dev->D.list, &devices); | 244 | dev->dev.class = &mISDN_class; |
| 96 | write_unlock_irqrestore(&device_lock, flags); | 245 | dev->dev.platform_data = dev; |
| 246 | dev->dev.parent = parent; | ||
| 247 | dev_set_drvdata(&dev->dev, dev); | ||
| 248 | |||
| 249 | err = device_add(&dev->dev); | ||
| 250 | if (err) | ||
| 251 | goto error3; | ||
| 97 | return 0; | 252 | return 0; |
| 253 | |||
| 254 | error3: | ||
| 255 | delete_stack(dev); | ||
| 256 | return err; | ||
| 257 | error1: | ||
| 258 | return err; | ||
| 259 | |||
| 98 | } | 260 | } |
| 99 | EXPORT_SYMBOL(mISDN_register_device); | 261 | EXPORT_SYMBOL(mISDN_register_device); |
| 100 | 262 | ||
| 101 | void | 263 | void |
| 102 | mISDN_unregister_device(struct mISDNdevice *dev) { | 264 | mISDN_unregister_device(struct mISDNdevice *dev) { |
| 103 | u_long flags; | ||
| 104 | |||
| 105 | if (debug & DEBUG_CORE) | 265 | if (debug & DEBUG_CORE) |
| 106 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", | 266 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", |
| 107 | dev_name(&dev->dev), dev->id); | 267 | dev_name(&dev->dev), dev->id); |
| 108 | write_lock_irqsave(&device_lock, flags); | 268 | /* sysfs_remove_link(&dev->dev.kobj, "device"); */ |
| 109 | list_del(&dev->D.list); | 269 | device_del(&dev->dev); |
| 110 | write_unlock_irqrestore(&device_lock, flags); | 270 | dev_set_drvdata(&dev->dev, NULL); |
| 271 | |||
| 111 | test_and_clear_bit(dev->id, (u_long *)&device_ids); | 272 | test_and_clear_bit(dev->id, (u_long *)&device_ids); |
| 112 | delete_stack(dev); | 273 | delete_stack(dev); |
| 274 | put_device(&dev->dev); | ||
| 113 | } | 275 | } |
| 114 | EXPORT_SYMBOL(mISDN_unregister_device); | 276 | EXPORT_SYMBOL(mISDN_unregister_device); |
| 115 | 277 | ||
| @@ -201,42 +363,43 @@ mISDNInit(void) | |||
| 201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | 363 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); |
| 202 | mISDN_init_clock(&debug); | 364 | mISDN_init_clock(&debug); |
| 203 | mISDN_initstack(&debug); | 365 | mISDN_initstack(&debug); |
| 366 | err = class_register(&mISDN_class); | ||
| 367 | if (err) | ||
| 368 | goto error1; | ||
| 204 | err = mISDN_inittimer(&debug); | 369 | err = mISDN_inittimer(&debug); |
| 205 | if (err) | 370 | if (err) |
| 206 | goto error; | 371 | goto error2; |
| 207 | err = l1_init(&debug); | 372 | err = l1_init(&debug); |
| 208 | if (err) { | 373 | if (err) |
| 209 | mISDN_timer_cleanup(); | 374 | goto error3; |
| 210 | goto error; | ||
| 211 | } | ||
| 212 | err = Isdnl2_Init(&debug); | 375 | err = Isdnl2_Init(&debug); |
| 213 | if (err) { | 376 | if (err) |
| 214 | mISDN_timer_cleanup(); | 377 | goto error4; |
| 215 | l1_cleanup(); | ||
| 216 | goto error; | ||
| 217 | } | ||
| 218 | err = misdn_sock_init(&debug); | 378 | err = misdn_sock_init(&debug); |
| 219 | if (err) { | 379 | if (err) |
| 220 | mISDN_timer_cleanup(); | 380 | goto error5; |
| 221 | l1_cleanup(); | 381 | return 0; |
| 222 | Isdnl2_cleanup(); | 382 | |
| 223 | } | 383 | error5: |
| 224 | error: | 384 | Isdnl2_cleanup(); |
| 385 | error4: | ||
| 386 | l1_cleanup(); | ||
| 387 | error3: | ||
| 388 | mISDN_timer_cleanup(); | ||
| 389 | error2: | ||
| 390 | class_unregister(&mISDN_class); | ||
| 391 | error1: | ||
| 225 | return err; | 392 | return err; |
| 226 | } | 393 | } |
| 227 | 394 | ||
| 228 | static void mISDN_cleanup(void) | 395 | static void mISDN_cleanup(void) |
| 229 | { | 396 | { |
| 230 | misdn_sock_cleanup(); | 397 | misdn_sock_cleanup(); |
| 231 | mISDN_timer_cleanup(); | ||
| 232 | l1_cleanup(); | ||
| 233 | Isdnl2_cleanup(); | 398 | Isdnl2_cleanup(); |
| 399 | l1_cleanup(); | ||
| 400 | mISDN_timer_cleanup(); | ||
| 401 | class_unregister(&mISDN_class); | ||
| 234 | 402 | ||
| 235 | if (!list_empty(&devices)) | ||
| 236 | printk(KERN_ERR "%s devices still registered\n", __func__); | ||
| 237 | |||
| 238 | if (!list_empty(&Bprotocols)) | ||
| 239 | printk(KERN_ERR "%s Bprotocols still registered\n", __func__); | ||
| 240 | printk(KERN_DEBUG "mISDNcore unloaded\n"); | 403 | printk(KERN_DEBUG "mISDNcore unloaded\n"); |
| 241 | } | 404 | } |
| 242 | 405 | ||
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index a6a9e1af2ad6..abe574989572 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c | |||
| @@ -1433,7 +1433,8 @@ init_card(struct l1oip *hc, int pri, int bundle) | |||
| 1433 | hc->chan[i + ch].bch = bch; | 1433 | hc->chan[i + ch].bch = bch; |
| 1434 | set_channelmap(bch->nr, dch->dev.channelmap); | 1434 | set_channelmap(bch->nr, dch->dev.channelmap); |
| 1435 | } | 1435 | } |
| 1436 | ret = mISDN_register_device(&dch->dev, hc->name); | 1436 | /* TODO: create a parent device for this driver */ |
| 1437 | ret = mISDN_register_device(&dch->dev, NULL, hc->name); | ||
| 1437 | if (ret) | 1438 | if (ret) |
| 1438 | return ret; | 1439 | return ret; |
| 1439 | hc->registered = 1; | 1440 | hc->registered = 1; |
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 3f9988849f32..d4229aebf648 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h | |||
| @@ -531,7 +531,8 @@ _queue_data(struct mISDNchannel *ch, u_int prim, | |||
| 531 | 531 | ||
| 532 | /* global register/unregister functions */ | 532 | /* global register/unregister functions */ |
| 533 | 533 | ||
| 534 | extern int mISDN_register_device(struct mISDNdevice *, char *name); | 534 | extern int mISDN_register_device(struct mISDNdevice *, |
| 535 | struct device *parent, char *name); | ||
| 535 | extern void mISDN_unregister_device(struct mISDNdevice *); | 536 | extern void mISDN_unregister_device(struct mISDNdevice *); |
| 536 | extern int mISDN_register_Bprotocol(struct Bprotocol *); | 537 | extern int mISDN_register_Bprotocol(struct Bprotocol *); |
| 537 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); | 538 | extern void mISDN_unregister_Bprotocol(struct Bprotocol *); |
| @@ -539,6 +540,11 @@ extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *, | |||
| 539 | void *); | 540 | void *); |
| 540 | extern void mISDN_unregister_clock(struct mISDNclock *); | 541 | extern void mISDN_unregister_clock(struct mISDNclock *); |
| 541 | 542 | ||
| 543 | static inline struct mISDNdevice *dev_to_mISDN(struct device *dev) | ||
| 544 | { | ||
| 545 | return dev_get_drvdata(dev); | ||
| 546 | } | ||
| 547 | |||
| 542 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); | 548 | extern void set_channel_address(struct mISDNchannel *, u_int, u_int); |
| 543 | extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *); | 549 | extern void mISDN_clock_update(struct mISDNclock *, int, struct timeval *); |
| 544 | extern unsigned short mISDN_clock_get(void); | 550 | extern unsigned short mISDN_clock_get(void); |
