diff options
author | Matthias Urlichs <smurf@smurf.noris.de> | 2008-08-15 18:09:24 -0400 |
---|---|---|
committer | Karsten Keil <kkeil@suse.de> | 2009-01-09 16:44:28 -0500 |
commit | b36b654a7e82308cea063cdf909a7f246105c2a3 (patch) | |
tree | 8c6fd2651a307a1b67549801796e2fdf8bc7991e /drivers/isdn | |
parent | 808a14a1583ca3790bf0a9c20c7d4cbac212c775 (diff) |
mISDN: Create /sys/class/mISDN
Create /sys/class/mISDN and implement functions to handle
device renames.
Signed-Off-By: Matthias Urlichs <matthias@urlichs.de>
Signed-off-by: Karsten Keil <kkeil@suse.de>
Diffstat (limited to 'drivers/isdn')
-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 |
4 files changed, 266 insertions, 114 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; |