• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/isdn/mISDN/
1/*
2 * Copyright 2008  by Karsten Keil <kkeil@novell.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/slab.h>
16#include <linux/types.h>
17#include <linux/stddef.h>
18#include <linux/module.h>
19#include <linux/spinlock.h>
20#include <linux/mISDNif.h>
21#include "core.h"
22
23static u_int debug;
24
25MODULE_AUTHOR("Karsten Keil");
26MODULE_LICENSE("GPL");
27module_param(debug, uint, S_IRUGO | S_IWUSR);
28
29static u64		device_ids;
30#define MAX_DEVICE_ID	63
31
32static LIST_HEAD(Bprotocols);
33static DEFINE_RWLOCK(bp_lock);
34
35static void mISDN_dev_release(struct device *dev)
36{
37	/* nothing to do: the device is part of its parent's data structure */
38}
39
40static ssize_t _show_id(struct device *dev,
41				struct device_attribute *attr, char *buf)
42{
43	struct mISDNdevice *mdev = dev_to_mISDN(dev);
44
45	if (!mdev)
46		return -ENODEV;
47	return sprintf(buf, "%d\n", mdev->id);
48}
49
50static ssize_t _show_nrbchan(struct device *dev,
51				struct device_attribute *attr, char *buf)
52{
53	struct mISDNdevice *mdev = dev_to_mISDN(dev);
54
55	if (!mdev)
56		return -ENODEV;
57	return sprintf(buf, "%d\n", mdev->nrbchan);
58}
59
60static ssize_t _show_d_protocols(struct device *dev,
61				struct device_attribute *attr, char *buf)
62{
63	struct mISDNdevice *mdev = dev_to_mISDN(dev);
64
65	if (!mdev)
66		return -ENODEV;
67	return sprintf(buf, "%d\n", mdev->Dprotocols);
68}
69
70static ssize_t _show_b_protocols(struct device *dev,
71				struct device_attribute *attr, char *buf)
72{
73	struct mISDNdevice *mdev = dev_to_mISDN(dev);
74
75	if (!mdev)
76		return -ENODEV;
77	return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
78}
79
80static ssize_t _show_protocol(struct device *dev,
81				struct device_attribute *attr, char *buf)
82{
83	struct mISDNdevice *mdev = dev_to_mISDN(dev);
84
85	if (!mdev)
86		return -ENODEV;
87	return sprintf(buf, "%d\n", mdev->D.protocol);
88}
89
90static ssize_t _show_name(struct device *dev,
91				struct device_attribute *attr, char *buf)
92{
93	strcpy(buf, dev_name(dev));
94	return strlen(buf);
95}
96
97
98static ssize_t _show_channelmap(struct device *dev,
99				struct device_attribute *attr, char *buf)
100{
101	struct mISDNdevice *mdev = dev_to_mISDN(dev);
102	char *bp = buf;
103	int i;
104
105	for (i = 0; i <= mdev->nrbchan; i++)
106		*bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0';
107
108	return bp - buf;
109}
110
111static struct device_attribute mISDN_dev_attrs[] = {
112	__ATTR(id,          S_IRUGO,         _show_id,          NULL),
113	__ATTR(d_protocols, S_IRUGO,         _show_d_protocols, NULL),
114	__ATTR(b_protocols, S_IRUGO,         _show_b_protocols, NULL),
115	__ATTR(protocol,    S_IRUGO,         _show_protocol,    NULL),
116	__ATTR(channelmap,  S_IRUGO,         _show_channelmap,  NULL),
117	__ATTR(nrbchan,     S_IRUGO,         _show_nrbchan,     NULL),
118	__ATTR(name,        S_IRUGO,         _show_name,        NULL),
119/*	__ATTR(name,        S_IRUGO|S_IWUSR, _show_name,       _set_name), */
120	{}
121};
122
123#ifdef CONFIG_HOTPLUG
124static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
125{
126	struct mISDNdevice *mdev = dev_to_mISDN(dev);
127
128	if (!mdev)
129		return 0;
130
131	if (add_uevent_var(env, "nchans=%d", mdev->nrbchan))
132		return -ENOMEM;
133
134	return 0;
135}
136#endif
137
138static void mISDN_class_release(struct class *cls)
139{
140	/* do nothing, it's static */
141}
142
143static struct class mISDN_class = {
144	.name = "mISDN",
145	.owner = THIS_MODULE,
146#ifdef CONFIG_HOTPLUG
147	.dev_uevent = mISDN_uevent,
148#endif
149	.dev_attrs = mISDN_dev_attrs,
150	.dev_release = mISDN_dev_release,
151	.class_release = mISDN_class_release,
152};
153
154static int
155_get_mdevice(struct device *dev, void *id)
156{
157	struct mISDNdevice *mdev = dev_to_mISDN(dev);
158
159	if (!mdev)
160		return 0;
161	if (mdev->id != *(u_int *)id)
162		return 0;
163	return 1;
164}
165
166struct mISDNdevice
167*get_mdevice(u_int id)
168{
169	return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id,
170		_get_mdevice));
171}
172
173static int
174_get_mdevice_count(struct device *dev, void *cnt)
175{
176	*(int *)cnt += 1;
177	return 0;
178}
179
180int
181get_mdevice_count(void)
182{
183	int cnt = 0;
184
185	class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count);
186	return cnt;
187}
188
189static int
190get_free_devid(void)
191{
192	u_int	i;
193
194	for (i = 0; i <= MAX_DEVICE_ID; i++)
195		if (!test_and_set_bit(i, (u_long *)&device_ids))
196			break;
197	if (i > MAX_DEVICE_ID)
198		return -EBUSY;
199	return i;
200}
201
202int
203mISDN_register_device(struct mISDNdevice *dev,
204			struct device *parent, char *name)
205{
206	int	err;
207
208	err = get_free_devid();
209	if (err < 0)
210		goto error1;
211	dev->id = err;
212
213	device_initialize(&dev->dev);
214	if (name && name[0])
215		dev_set_name(&dev->dev, "%s", name);
216	else
217		dev_set_name(&dev->dev, "mISDN%d", dev->id);
218	if (debug & DEBUG_CORE)
219		printk(KERN_DEBUG "mISDN_register %s %d\n",
220			dev_name(&dev->dev), dev->id);
221	err = create_stack(dev);
222	if (err)
223		goto error1;
224
225	dev->dev.class = &mISDN_class;
226	dev->dev.platform_data = dev;
227	dev->dev.parent = parent;
228	dev_set_drvdata(&dev->dev, dev);
229
230	err = device_add(&dev->dev);
231	if (err)
232		goto error3;
233	return 0;
234
235error3:
236	delete_stack(dev);
237	return err;
238error1:
239	return err;
240
241}
242EXPORT_SYMBOL(mISDN_register_device);
243
244void
245mISDN_unregister_device(struct mISDNdevice *dev) {
246	if (debug & DEBUG_CORE)
247		printk(KERN_DEBUG "mISDN_unregister %s %d\n",
248			dev_name(&dev->dev), dev->id);
249	/* sysfs_remove_link(&dev->dev.kobj, "device"); */
250	device_del(&dev->dev);
251	dev_set_drvdata(&dev->dev, NULL);
252
253	test_and_clear_bit(dev->id, (u_long *)&device_ids);
254	delete_stack(dev);
255	put_device(&dev->dev);
256}
257EXPORT_SYMBOL(mISDN_unregister_device);
258
259u_int
260get_all_Bprotocols(void)
261{
262	struct Bprotocol	*bp;
263	u_int	m = 0;
264
265	read_lock(&bp_lock);
266	list_for_each_entry(bp, &Bprotocols, list)
267		m |= bp->Bprotocols;
268	read_unlock(&bp_lock);
269	return m;
270}
271
272struct Bprotocol *
273get_Bprotocol4mask(u_int m)
274{
275	struct Bprotocol	*bp;
276
277	read_lock(&bp_lock);
278	list_for_each_entry(bp, &Bprotocols, list)
279		if (bp->Bprotocols & m) {
280			read_unlock(&bp_lock);
281			return bp;
282		}
283	read_unlock(&bp_lock);
284	return NULL;
285}
286
287struct Bprotocol *
288get_Bprotocol4id(u_int id)
289{
290	u_int	m;
291
292	if (id < ISDN_P_B_START || id > 63) {
293		printk(KERN_WARNING "%s id not in range  %d\n",
294		    __func__, id);
295		return NULL;
296	}
297	m = 1 << (id & ISDN_P_B_MASK);
298	return get_Bprotocol4mask(m);
299}
300
301int
302mISDN_register_Bprotocol(struct Bprotocol *bp)
303{
304	u_long			flags;
305	struct Bprotocol	*old;
306
307	if (debug & DEBUG_CORE)
308		printk(KERN_DEBUG "%s: %s/%x\n", __func__,
309		    bp->name, bp->Bprotocols);
310	old = get_Bprotocol4mask(bp->Bprotocols);
311	if (old) {
312		printk(KERN_WARNING
313		    "register duplicate protocol old %s/%x new %s/%x\n",
314		    old->name, old->Bprotocols, bp->name, bp->Bprotocols);
315		return -EBUSY;
316	}
317	write_lock_irqsave(&bp_lock, flags);
318	list_add_tail(&bp->list, &Bprotocols);
319	write_unlock_irqrestore(&bp_lock, flags);
320	return 0;
321}
322EXPORT_SYMBOL(mISDN_register_Bprotocol);
323
324void
325mISDN_unregister_Bprotocol(struct Bprotocol *bp)
326{
327	u_long	flags;
328
329	if (debug & DEBUG_CORE)
330		printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name,
331			bp->Bprotocols);
332	write_lock_irqsave(&bp_lock, flags);
333	list_del(&bp->list);
334	write_unlock_irqrestore(&bp_lock, flags);
335}
336EXPORT_SYMBOL(mISDN_unregister_Bprotocol);
337
338static int
339mISDNInit(void)
340{
341	int	err;
342
343	printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n",
344		MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE);
345	mISDN_init_clock(&debug);
346	mISDN_initstack(&debug);
347	err = class_register(&mISDN_class);
348	if (err)
349		goto error1;
350	err = mISDN_inittimer(&debug);
351	if (err)
352		goto error2;
353	err = l1_init(&debug);
354	if (err)
355		goto error3;
356	err = Isdnl2_Init(&debug);
357	if (err)
358		goto error4;
359	err = misdn_sock_init(&debug);
360	if (err)
361		goto error5;
362	return 0;
363
364error5:
365	Isdnl2_cleanup();
366error4:
367	l1_cleanup();
368error3:
369	mISDN_timer_cleanup();
370error2:
371	class_unregister(&mISDN_class);
372error1:
373	return err;
374}
375
376static void mISDN_cleanup(void)
377{
378	misdn_sock_cleanup();
379	Isdnl2_cleanup();
380	l1_cleanup();
381	mISDN_timer_cleanup();
382	class_unregister(&mISDN_class);
383
384	printk(KERN_DEBUG "mISDNcore unloaded\n");
385}
386
387module_init(mISDNInit);
388module_exit(mISDN_cleanup);
389