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/mISDN | |
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/mISDN')
-rw-r--r-- | drivers/isdn/mISDN/core.c | 271 | ||||
-rw-r--r-- | drivers/isdn/mISDN/l1oip_core.c | 3 |
2 files changed, 219 insertions, 55 deletions
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; |