blob: 0b4c8a7396bc934d0c0a15ada3e944d313aae29c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
2 *
3 * Kernel CAPI 2.0 Module
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
Robert P. J. Day37772ac2008-04-28 02:14:42 -070013#define AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
15#include "kcapi.h"
16#include <linux/module.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/proc_fs.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040021#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/seq_file.h>
23#include <linux/skbuff.h>
24#include <linux/workqueue.h>
25#include <linux/capi.h>
26#include <linux/kernelcapi.h>
27#include <linux/init.h>
28#include <linux/moduleparam.h>
29#include <linux/delay.h>
30#include <asm/uaccess.h>
31#include <linux/isdn/capicmd.h>
32#include <linux/isdn/capiutil.h>
Robert P. J. Day37772ac2008-04-28 02:14:42 -070033#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/b1lli.h>
35#endif
Arjan van de Ven9cdf1822006-03-23 03:00:21 -080036#include <linux/mutex.h>
Jan Kiszka88c896e2010-02-08 10:12:15 +000037#include <linux/rcupdate.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static int showcapimsgs = 0;
40
41MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
42MODULE_AUTHOR("Carsten Paeth");
43MODULE_LICENSE("GPL");
44module_param(showcapimsgs, uint, 0);
45
46/* ------------------------------------------------------------- */
47
Jan Kiszkaef69bb22010-02-08 10:12:13 +000048struct capictr_event {
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 struct work_struct work;
Jan Kiszkaef69bb22010-02-08 10:12:13 +000050 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 u32 controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052};
53
54/* ------------------------------------------------------------- */
55
56static struct capi_version driver_version = {2, 0, 1, 1<<4};
57static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
58static char capi_manufakturer[64] = "AVM Berlin";
59
60#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
61
62LIST_HEAD(capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +000063DEFINE_MUTEX(capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Jan Kiszka0ca3a012010-02-08 10:12:14 +000065struct capi_ctr *capi_controller[CAPI_MAXCONTR];
66DEFINE_MUTEX(capi_controller_lock);
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068struct capi20_appl *capi_applications[CAPI_MAXAPPL];
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Jan Kiszka52253032010-02-08 10:12:10 +000070static int ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jan Kiszkaef69bb22010-02-08 10:12:13 +000072static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/* -------- controller ref counting -------------------------------------- */
75
76static inline struct capi_ctr *
Jan Kiszka52253032010-02-08 10:12:10 +000077capi_ctr_get(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
Jan Kiszka52253032010-02-08 10:12:10 +000079 if (!try_module_get(ctr->owner))
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 return NULL;
Jan Kiszka52253032010-02-08 10:12:10 +000081 return ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
84static inline void
Jan Kiszka52253032010-02-08 10:12:10 +000085capi_ctr_put(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
Jan Kiszka52253032010-02-08 10:12:10 +000087 module_put(ctr->owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
90/* ------------------------------------------------------------- */
91
92static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
93{
94 if (contr - 1 >= CAPI_MAXCONTR)
95 return NULL;
96
Jan Kiszka52253032010-02-08 10:12:10 +000097 return capi_controller[contr - 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
101{
102 if (applid - 1 >= CAPI_MAXAPPL)
103 return NULL;
104
Jan Kiszka88c896e2010-02-08 10:12:15 +0000105 return rcu_dereference(capi_applications[applid - 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106}
107
108/* -------- util functions ------------------------------------ */
109
110static inline int capi_cmd_valid(u8 cmd)
111{
112 switch (cmd) {
113 case CAPI_ALERT:
114 case CAPI_CONNECT:
115 case CAPI_CONNECT_ACTIVE:
116 case CAPI_CONNECT_B3_ACTIVE:
117 case CAPI_CONNECT_B3:
118 case CAPI_CONNECT_B3_T90_ACTIVE:
119 case CAPI_DATA_B3:
120 case CAPI_DISCONNECT_B3:
121 case CAPI_DISCONNECT:
122 case CAPI_FACILITY:
123 case CAPI_INFO:
124 case CAPI_LISTEN:
125 case CAPI_MANUFACTURER:
126 case CAPI_RESET_B3:
127 case CAPI_SELECT_B_PROTOCOL:
128 return 1;
129 }
130 return 0;
131}
132
133static inline int capi_subcmd_valid(u8 subcmd)
134{
135 switch (subcmd) {
136 case CAPI_REQ:
137 case CAPI_CONF:
138 case CAPI_IND:
139 case CAPI_RESP:
140 return 1;
141 }
142 return 0;
143}
144
145/* ------------------------------------------------------------ */
146
Jan Kiszka52253032010-02-08 10:12:10 +0000147static void
148register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Jan Kiszka52253032010-02-08 10:12:10 +0000150 ctr = capi_ctr_get(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Jan Kiszka52253032010-02-08 10:12:10 +0000152 if (ctr)
153 ctr->register_appl(ctr, applid, rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 else
Jan Kiszka52253032010-02-08 10:12:10 +0000155 printk(KERN_WARNING "%s: cannot get controller resources\n",
156 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159
Jan Kiszka52253032010-02-08 10:12:10 +0000160static void release_appl(struct capi_ctr *ctr, u16 applid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
162 DBG("applid %#x", applid);
163
Jan Kiszka52253032010-02-08 10:12:10 +0000164 ctr->release_appl(ctr, applid);
165 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166}
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168static void notify_up(u32 contr)
169{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 struct capi20_appl *ap;
Jan Kiszka3efecf72010-02-08 10:12:12 +0000171 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 u16 applid;
173
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000174 mutex_lock(&capi_controller_lock);
175
Jan Kiszka3efecf72010-02-08 10:12:12 +0000176 if (showcapimsgs & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000178
179 ctr = get_capi_ctr_by_nr(contr);
180 if (ctr) {
181 if (ctr->state == CAPI_CTR_RUNNING)
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000182 goto unlock_out;
Jan Kiszka3efecf72010-02-08 10:12:12 +0000183
184 ctr->state = CAPI_CTR_RUNNING;
185
186 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
187 ap = get_capi_appl_by_nr(applid);
Jan Kiszka88c896e2010-02-08 10:12:15 +0000188 if (!ap)
Jan Kiszka3efecf72010-02-08 10:12:12 +0000189 continue;
190 register_appl(ctr, applid, &ap->rparam);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000191 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000192
193 wake_up_interruptible_all(&ctr->state_wait_queue);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000194 } else
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700195 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000196
197unlock_out:
198 mutex_unlock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000201static void ctr_down(struct capi_ctr *ctr, int new_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 struct capi20_appl *ap;
204 u16 applid;
205
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000206 if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED)
Jan Kiszka3efecf72010-02-08 10:12:12 +0000207 return;
208
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000209 ctr->state = new_state;
Jan Kiszka3efecf72010-02-08 10:12:12 +0000210
211 memset(ctr->manu, 0, sizeof(ctr->manu));
212 memset(&ctr->version, 0, sizeof(ctr->version));
213 memset(&ctr->profile, 0, sizeof(ctr->profile));
214 memset(ctr->serial, 0, sizeof(ctr->serial));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
217 ap = get_capi_appl_by_nr(applid);
Jan Kiszka88c896e2010-02-08 10:12:15 +0000218 if (ap)
Jan Kiszka3efecf72010-02-08 10:12:12 +0000219 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000221
222 wake_up_interruptible_all(&ctr->state_wait_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
Jan Kiszka3efecf72010-02-08 10:12:12 +0000225static void notify_down(u32 contr)
226{
227 struct capi_ctr *ctr;
228
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000229 mutex_lock(&capi_controller_lock);
230
Jan Kiszka3efecf72010-02-08 10:12:12 +0000231 if (showcapimsgs & 1)
232 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
233
234 ctr = get_capi_ctr_by_nr(contr);
235 if (ctr)
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000236 ctr_down(ctr, CAPI_CTR_DETECTED);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000237 else
238 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000239
240 mutex_unlock(&capi_controller_lock);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000241}
242
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000243static int
244notify_handler(struct notifier_block *nb, unsigned long val, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000246 u32 contr = (long)v;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000248 switch (val) {
249 case CAPICTR_UP:
250 notify_up(contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 break;
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000252 case CAPICTR_DOWN:
253 notify_down(contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 break;
255 }
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000256 return NOTIFY_OK;
257}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000259static void do_notify_work(struct work_struct *work)
260{
261 struct capictr_event *event =
262 container_of(work, struct capictr_event, work);
263
264 blocking_notifier_call_chain(&ctr_notifier_list, event->type,
265 (void *)(long)event->controller);
266 kfree(event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
269/*
270 * The notifier will result in adding/deleteing of devices. Devices can
271 * only removed in user process, not in bh.
272 */
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000273static int notify_push(unsigned int event_type, u32 controller)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000275 struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000277 if (!event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return -ENOMEM;
279
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000280 INIT_WORK(&event->work, do_notify_work);
281 event->type = event_type;
282 event->controller = controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000284 schedule_work(&event->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return 0;
286}
287
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000288int register_capictr_notifier(struct notifier_block *nb)
289{
290 return blocking_notifier_chain_register(&ctr_notifier_list, nb);
291}
292EXPORT_SYMBOL_GPL(register_capictr_notifier);
293
294int unregister_capictr_notifier(struct notifier_block *nb)
295{
296 return blocking_notifier_chain_unregister(&ctr_notifier_list, nb);
297}
298EXPORT_SYMBOL_GPL(unregister_capictr_notifier);
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300/* -------- Receiver ------------------------------------------ */
301
David Howellsc4028952006-11-22 14:57:56 +0000302static void recv_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 struct sk_buff *skb;
David Howellsc4028952006-11-22 14:57:56 +0000305 struct capi20_appl *ap =
306 container_of(work, struct capi20_appl, recv_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 if ((!ap) || (ap->release_in_progress))
309 return;
310
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700311 mutex_lock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 while ((skb = skb_dequeue(&ap->recv_queue))) {
313 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
314 ap->nrecvdatapkt++;
315 else
316 ap->nrecvctlpkt++;
317
318 ap->recv_message(ap, skb);
319 }
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700320 mutex_unlock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
322
Tilman Schmidt554f2002009-04-23 02:24:21 +0000323/**
324 * capi_ctr_handle_message() - handle incoming CAPI message
Jan Kiszka52253032010-02-08 10:12:10 +0000325 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000326 * @appl: application ID.
327 * @skb: message.
328 *
329 * Called by hardware driver to pass a CAPI message to the application.
330 */
331
Jan Kiszka52253032010-02-08 10:12:10 +0000332void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
333 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 struct capi20_appl *ap;
336 int showctl = 0;
337 u8 cmd, subcmd;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800338 _cdebbuf *cdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Jan Kiszka52253032010-02-08 10:12:10 +0000340 if (ctr->state != CAPI_CTR_RUNNING) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800341 cdb = capi_message2str(skb->data);
342 if (cdb) {
343 printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
Jan Kiszka52253032010-02-08 10:12:10 +0000344 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800345 cdebbuf_free(cdb);
346 } else
347 printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000348 ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 goto error;
350 }
351
352 cmd = CAPIMSG_COMMAND(skb->data);
353 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
354 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
Jan Kiszka52253032010-02-08 10:12:10 +0000355 ctr->nrecvdatapkt++;
356 if (ctr->traceflag > 2)
357 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000359 ctr->nrecvctlpkt++;
360 if (ctr->traceflag)
361 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Jan Kiszka52253032010-02-08 10:12:10 +0000363 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (showctl & 2) {
365 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800366 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000367 ctr->cnr, CAPIMSG_APPID(skb->data),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 capi_cmd2str(cmd, subcmd),
369 CAPIMSG_LEN(skb->data));
370 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800371 cdb = capi_message2str(skb->data);
372 if (cdb) {
373 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000374 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800375 cdebbuf_free(cdb);
376 } else
377 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000378 ctr->cnr, CAPIMSG_APPID(skb->data),
Karsten Keil17f0cd22007-02-28 20:13:50 -0800379 capi_cmd2str(cmd, subcmd),
380 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
382
383 }
384
Jan Kiszka88c896e2010-02-08 10:12:15 +0000385 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
Jan Kiszka88c896e2010-02-08 10:12:15 +0000387 if (!ap) {
388 rcu_read_unlock();
Karsten Keil17f0cd22007-02-28 20:13:50 -0800389 cdb = capi_message2str(skb->data);
390 if (cdb) {
391 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
392 CAPIMSG_APPID(skb->data), cdb->buf);
393 cdebbuf_free(cdb);
394 } else
395 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
396 CAPIMSG_APPID(skb->data),
397 capi_cmd2str(cmd, subcmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 goto error;
399 }
400 skb_queue_tail(&ap->recv_queue, skb);
401 schedule_work(&ap->recv_work);
Jan Kiszka88c896e2010-02-08 10:12:15 +0000402 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 return;
405
406error:
407 kfree_skb(skb);
408}
409
410EXPORT_SYMBOL(capi_ctr_handle_message);
411
Tilman Schmidt554f2002009-04-23 02:24:21 +0000412/**
413 * capi_ctr_ready() - signal CAPI controller ready
Jan Kiszka52253032010-02-08 10:12:10 +0000414 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000415 *
416 * Called by hardware driver to signal that the controller is up and running.
417 */
418
Jan Kiszka52253032010-02-08 10:12:10 +0000419void capi_ctr_ready(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
Jan Kiszka52253032010-02-08 10:12:10 +0000421 printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
422 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000424 notify_push(CAPICTR_UP, ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
427EXPORT_SYMBOL(capi_ctr_ready);
428
Tilman Schmidt554f2002009-04-23 02:24:21 +0000429/**
Tilman Schmidt4e329972009-06-07 09:09:23 +0000430 * capi_ctr_down() - signal CAPI controller not ready
Jan Kiszka52253032010-02-08 10:12:10 +0000431 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000432 *
433 * Called by hardware driver to signal that the controller is down and
434 * unavailable for use.
435 */
436
Jan Kiszka52253032010-02-08 10:12:10 +0000437void capi_ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Jan Kiszka52253032010-02-08 10:12:10 +0000439 printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000441 notify_push(CAPICTR_DOWN, ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
Tilman Schmidt4e329972009-06-07 09:09:23 +0000444EXPORT_SYMBOL(capi_ctr_down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Tilman Schmidt554f2002009-04-23 02:24:21 +0000446/**
447 * capi_ctr_suspend_output() - suspend controller
Jan Kiszka52253032010-02-08 10:12:10 +0000448 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000449 *
450 * Called by hardware driver to stop data flow.
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000451 *
452 * Note: The caller is responsible for synchronizing concurrent state changes
453 * as well as invocations of capi_ctr_handle_message.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000454 */
455
Jan Kiszka52253032010-02-08 10:12:10 +0000456void capi_ctr_suspend_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
Jan Kiszka52253032010-02-08 10:12:10 +0000458 if (!ctr->blocked) {
459 printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
460 ctr->cnr);
461 ctr->blocked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463}
464
465EXPORT_SYMBOL(capi_ctr_suspend_output);
466
Tilman Schmidt554f2002009-04-23 02:24:21 +0000467/**
468 * capi_ctr_resume_output() - resume controller
Jan Kiszka52253032010-02-08 10:12:10 +0000469 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000470 *
471 * Called by hardware driver to resume data flow.
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000472 *
473 * Note: The caller is responsible for synchronizing concurrent state changes
474 * as well as invocations of capi_ctr_handle_message.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000475 */
476
Jan Kiszka52253032010-02-08 10:12:10 +0000477void capi_ctr_resume_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Jan Kiszka52253032010-02-08 10:12:10 +0000479 if (ctr->blocked) {
480 printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
481 ctr->cnr);
482 ctr->blocked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484}
485
486EXPORT_SYMBOL(capi_ctr_resume_output);
487
488/* ------------------------------------------------------------- */
489
Tilman Schmidt554f2002009-04-23 02:24:21 +0000490/**
491 * attach_capi_ctr() - register CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000492 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000493 *
494 * Called by hardware driver to register a controller with the CAPI subsystem.
495 * Return value: 0 on success, error code < 0 on error
496 */
497
Jan Kiszka52253032010-02-08 10:12:10 +0000498int attach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 int i;
501
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000502 mutex_lock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000505 if (!capi_controller[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 break;
507 }
508 if (i == CAPI_MAXCONTR) {
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000509 mutex_unlock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 printk(KERN_ERR "kcapi: out of controller slots\n");
511 return -EBUSY;
512 }
Jan Kiszka52253032010-02-08 10:12:10 +0000513 capi_controller[i] = ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Jan Kiszka52253032010-02-08 10:12:10 +0000515 ctr->nrecvctlpkt = 0;
516 ctr->nrecvdatapkt = 0;
517 ctr->nsentctlpkt = 0;
518 ctr->nsentdatapkt = 0;
519 ctr->cnr = i + 1;
520 ctr->state = CAPI_CTR_DETECTED;
521 ctr->blocked = 0;
522 ctr->traceflag = showcapimsgs;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000523 init_waitqueue_head(&ctr->state_wait_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Jan Kiszka52253032010-02-08 10:12:10 +0000525 sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
526 ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Jan Kiszka52253032010-02-08 10:12:10 +0000528 ncontrollers++;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000529
530 mutex_unlock(&capi_controller_lock);
531
Jan Kiszka52253032010-02-08 10:12:10 +0000532 printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
533 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 return 0;
535}
536
537EXPORT_SYMBOL(attach_capi_ctr);
538
Tilman Schmidt554f2002009-04-23 02:24:21 +0000539/**
540 * detach_capi_ctr() - unregister CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000541 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000542 *
543 * Called by hardware driver to remove the registration of a controller
544 * with the CAPI subsystem.
545 * Return value: 0 on success, error code < 0 on error
546 */
547
Jan Kiszka52253032010-02-08 10:12:10 +0000548int detach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000550 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000552 mutex_lock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000554 ctr_down(ctr, CAPI_CTR_DETACHED);
555
556 if (capi_controller[ctr->cnr - 1] != ctr) {
557 err = -EINVAL;
558 goto unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
Jan Kiszka52253032010-02-08 10:12:10 +0000560 capi_controller[ctr->cnr - 1] = NULL;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000561 ncontrollers--;
562
563 if (ctr->procent)
564 remove_proc_entry(ctr->procfn, NULL);
565
Jan Kiszka52253032010-02-08 10:12:10 +0000566 printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
567 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000569unlock_out:
570 mutex_unlock(&capi_controller_lock);
571
572 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
575EXPORT_SYMBOL(detach_capi_ctr);
576
Tilman Schmidt554f2002009-04-23 02:24:21 +0000577/**
578 * register_capi_driver() - register CAPI driver
579 * @driver: driver descriptor structure.
580 *
581 * Called by hardware driver to register itself with the CAPI subsystem.
582 */
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584void register_capi_driver(struct capi_driver *driver)
585{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000586 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 list_add_tail(&driver->list, &capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000588 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589}
590
591EXPORT_SYMBOL(register_capi_driver);
592
Tilman Schmidt554f2002009-04-23 02:24:21 +0000593/**
594 * unregister_capi_driver() - unregister CAPI driver
595 * @driver: driver descriptor structure.
596 *
597 * Called by hardware driver to unregister itself from the CAPI subsystem.
598 */
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600void unregister_capi_driver(struct capi_driver *driver)
601{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000602 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 list_del(&driver->list);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000604 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
607EXPORT_SYMBOL(unregister_capi_driver);
608
609/* ------------------------------------------------------------- */
610/* -------- CAPI2.0 Interface ---------------------------------- */
611/* ------------------------------------------------------------- */
612
Tilman Schmidt554f2002009-04-23 02:24:21 +0000613/**
614 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
615 *
616 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
617 * is ready for use, CAPI_REGNOTINSTALLED otherwise)
618 */
619
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620u16 capi20_isinstalled(void)
621{
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000622 u16 ret = CAPI_REGNOTINSTALLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 int i;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000624
625 mutex_lock(&capi_controller_lock);
626
627 for (i = 0; i < CAPI_MAXCONTR; i++)
Jan Kiszka52253032010-02-08 10:12:10 +0000628 if (capi_controller[i] &&
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000629 capi_controller[i]->state == CAPI_CTR_RUNNING) {
630 ret = CAPI_NOERROR;
631 break;
632 }
633
634 mutex_unlock(&capi_controller_lock);
635
636 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639EXPORT_SYMBOL(capi20_isinstalled);
640
Tilman Schmidt554f2002009-04-23 02:24:21 +0000641/**
642 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
643 * @ap: CAPI application descriptor structure.
644 *
645 * Register an application's presence with CAPI.
646 * A unique application ID is assigned and stored in @ap->applid.
647 * After this function returns successfully, the message receive
648 * callback function @ap->recv_message() may be called at any time
649 * until capi20_release() has been called for the same @ap.
650 * Return value: CAPI result code
651 */
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653u16 capi20_register(struct capi20_appl *ap)
654{
655 int i;
656 u16 applid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
658 DBG("");
659
660 if (ap->rparam.datablklen < 128)
661 return CAPI_LOGBLKSIZETOSMALL;
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 ap->nrecvctlpkt = 0;
664 ap->nrecvdatapkt = 0;
665 ap->nsentctlpkt = 0;
666 ap->nsentdatapkt = 0;
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700667 mutex_init(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 skb_queue_head_init(&ap->recv_queue);
David Howellsc4028952006-11-22 14:57:56 +0000669 INIT_WORK(&ap->recv_work, recv_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 ap->release_in_progress = 0;
671
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000672 mutex_lock(&capi_controller_lock);
673
Jan Kiszka88c896e2010-02-08 10:12:15 +0000674 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
675 if (capi_applications[applid - 1] == NULL)
676 break;
677 }
678 if (applid > CAPI_MAXAPPL) {
679 mutex_unlock(&capi_controller_lock);
680 return CAPI_TOOMANYAPPLS;
681 }
682
683 ap->applid = applid;
684 capi_applications[applid - 1] = ap;
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000687 if (!capi_controller[i] ||
688 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000690 register_appl(capi_controller[i], applid, &ap->rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000692
693 mutex_unlock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 if (showcapimsgs & 1) {
696 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
697 }
698
699 return CAPI_NOERROR;
700}
701
702EXPORT_SYMBOL(capi20_register);
703
Tilman Schmidt554f2002009-04-23 02:24:21 +0000704/**
705 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
706 * @ap: CAPI application descriptor structure.
707 *
708 * Terminate an application's registration with CAPI.
709 * After this function returns successfully, the message receive
710 * callback function @ap->recv_message() will no longer be called.
711 * Return value: CAPI result code
712 */
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714u16 capi20_release(struct capi20_appl *ap)
715{
716 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 DBG("applid %#x", ap->applid);
719
Jan Kiszka88c896e2010-02-08 10:12:15 +0000720 mutex_lock(&capi_controller_lock);
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 ap->release_in_progress = 1;
723 capi_applications[ap->applid - 1] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Jan Kiszka88c896e2010-02-08 10:12:15 +0000725 synchronize_rcu();
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000728 if (!capi_controller[i] ||
729 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000731 release_appl(capi_controller[i], ap->applid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000733
734 mutex_unlock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 flush_scheduled_work();
737 skb_queue_purge(&ap->recv_queue);
738
739 if (showcapimsgs & 1) {
740 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
741 }
742
743 return CAPI_NOERROR;
744}
745
746EXPORT_SYMBOL(capi20_release);
747
Tilman Schmidt554f2002009-04-23 02:24:21 +0000748/**
749 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
750 * @ap: CAPI application descriptor structure.
751 * @skb: CAPI message.
752 *
753 * Transfer a single message to CAPI.
754 * Return value: CAPI result code
755 */
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
758{
Jan Kiszka52253032010-02-08 10:12:10 +0000759 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 int showctl = 0;
761 u8 cmd, subcmd;
762
763 DBG("applid %#x", ap->applid);
764
Jan Kiszka52253032010-02-08 10:12:10 +0000765 if (ncontrollers == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return CAPI_REGNOTINSTALLED;
767 if ((ap->applid == 0) || ap->release_in_progress)
768 return CAPI_ILLAPPNR;
769 if (skb->len < 12
770 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
771 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
772 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000773
774 /*
775 * The controller reference is protected by the existence of the
776 * application passed to us. We assume that the caller properly
777 * synchronizes this service with capi20_release.
778 */
Jan Kiszka52253032010-02-08 10:12:10 +0000779 ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
780 if (!ctr || ctr->state != CAPI_CTR_RUNNING) {
781 ctr = get_capi_ctr_by_nr(1); /* XXX why? */
782 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return CAPI_REGNOTINSTALLED;
784 }
Jan Kiszka52253032010-02-08 10:12:10 +0000785 if (ctr->blocked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return CAPI_SENDQUEUEFULL;
787
788 cmd = CAPIMSG_COMMAND(skb->data);
789 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
790
791 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
Jan Kiszka52253032010-02-08 10:12:10 +0000792 ctr->nsentdatapkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 ap->nsentdatapkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000794 if (ctr->traceflag > 2)
795 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000797 ctr->nsentctlpkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 ap->nsentctlpkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000799 if (ctr->traceflag)
800 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
Jan Kiszka52253032010-02-08 10:12:10 +0000802 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (showctl & 2) {
804 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800805 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 CAPIMSG_CONTROLLER(skb->data),
807 CAPIMSG_APPID(skb->data),
808 capi_cmd2str(cmd, subcmd),
809 CAPIMSG_LEN(skb->data));
810 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800811 _cdebbuf *cdb = capi_message2str(skb->data);
812 if (cdb) {
813 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
814 CAPIMSG_CONTROLLER(skb->data),
815 cdb->buf);
816 cdebbuf_free(cdb);
817 } else
818 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
819 CAPIMSG_CONTROLLER(skb->data),
820 CAPIMSG_APPID(skb->data),
821 capi_cmd2str(cmd, subcmd),
822 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
Jan Kiszka52253032010-02-08 10:12:10 +0000825 return ctr->send_message(ctr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826}
827
828EXPORT_SYMBOL(capi20_put_message);
829
Tilman Schmidt554f2002009-04-23 02:24:21 +0000830/**
831 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
832 * @contr: controller number.
833 * @buf: result buffer (64 bytes).
834 *
835 * Retrieve information about the manufacturer of the specified ISDN controller
836 * or (for @contr == 0) the driver itself.
837 * Return value: CAPI result code
838 */
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840u16 capi20_get_manufacturer(u32 contr, u8 *buf)
841{
Jan Kiszka52253032010-02-08 10:12:10 +0000842 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000843 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if (contr == 0) {
846 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
847 return CAPI_NOERROR;
848 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000849
850 mutex_lock(&capi_controller_lock);
851
Jan Kiszka52253032010-02-08 10:12:10 +0000852 ctr = get_capi_ctr_by_nr(contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000853 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
854 strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
855 ret = CAPI_NOERROR;
856 } else
857 ret = CAPI_REGNOTINSTALLED;
858
859 mutex_unlock(&capi_controller_lock);
860 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
863EXPORT_SYMBOL(capi20_get_manufacturer);
864
Tilman Schmidt554f2002009-04-23 02:24:21 +0000865/**
866 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
867 * @contr: controller number.
868 * @verp: result structure.
869 *
870 * Retrieve version information for the specified ISDN controller
871 * or (for @contr == 0) the driver itself.
872 * Return value: CAPI result code
873 */
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875u16 capi20_get_version(u32 contr, struct capi_version *verp)
876{
Jan Kiszka52253032010-02-08 10:12:10 +0000877 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000878 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 if (contr == 0) {
881 *verp = driver_version;
882 return CAPI_NOERROR;
883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000885 mutex_lock(&capi_controller_lock);
886
887 ctr = get_capi_ctr_by_nr(contr);
888 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
889 memcpy(verp, &ctr->version, sizeof(capi_version));
890 ret = CAPI_NOERROR;
891 } else
892 ret = CAPI_REGNOTINSTALLED;
893
894 mutex_unlock(&capi_controller_lock);
895 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
898EXPORT_SYMBOL(capi20_get_version);
899
Tilman Schmidt554f2002009-04-23 02:24:21 +0000900/**
901 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
902 * @contr: controller number.
903 * @serial: result buffer (8 bytes).
904 *
905 * Retrieve the serial number of the specified ISDN controller
906 * or (for @contr == 0) the driver itself.
907 * Return value: CAPI result code
908 */
909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910u16 capi20_get_serial(u32 contr, u8 *serial)
911{
Jan Kiszka52253032010-02-08 10:12:10 +0000912 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000913 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 if (contr == 0) {
916 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
917 return CAPI_NOERROR;
918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000920 mutex_lock(&capi_controller_lock);
921
922 ctr = get_capi_ctr_by_nr(contr);
923 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
924 strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
925 ret = CAPI_NOERROR;
926 } else
927 ret = CAPI_REGNOTINSTALLED;
928
929 mutex_unlock(&capi_controller_lock);
930 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931}
932
933EXPORT_SYMBOL(capi20_get_serial);
934
Tilman Schmidt554f2002009-04-23 02:24:21 +0000935/**
936 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
937 * @contr: controller number.
938 * @profp: result structure.
939 *
940 * Retrieve capability information for the specified ISDN controller
941 * or (for @contr == 0) the number of installed controllers.
942 * Return value: CAPI result code
943 */
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
946{
Jan Kiszka52253032010-02-08 10:12:10 +0000947 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000948 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 if (contr == 0) {
Jan Kiszka52253032010-02-08 10:12:10 +0000951 profp->ncontroller = ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 return CAPI_NOERROR;
953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000955 mutex_lock(&capi_controller_lock);
956
957 ctr = get_capi_ctr_by_nr(contr);
958 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
959 memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
960 ret = CAPI_NOERROR;
961 } else
962 ret = CAPI_REGNOTINSTALLED;
963
964 mutex_unlock(&capi_controller_lock);
965 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
968EXPORT_SYMBOL(capi20_get_profile);
969
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000970/* Must be called with capi_controller_lock held. */
971static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state)
972{
973 DEFINE_WAIT(wait);
974 int retval = 0;
975
976 ctr = capi_ctr_get(ctr);
977 if (!ctr)
978 return -ESRCH;
979
980 for (;;) {
981 prepare_to_wait(&ctr->state_wait_queue, &wait,
982 TASK_INTERRUPTIBLE);
983
984 if (ctr->state == state)
985 break;
986 if (ctr->state == CAPI_CTR_DETACHED) {
987 retval = -ESRCH;
988 break;
989 }
990 if (signal_pending(current)) {
991 retval = -EINTR;
992 break;
993 }
994
995 mutex_unlock(&capi_controller_lock);
996 schedule();
997 mutex_lock(&capi_controller_lock);
998 }
999 finish_wait(&ctr->state_wait_queue, &wait);
1000
1001 capi_ctr_put(ctr);
1002
1003 return retval;
1004}
1005
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001006#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007static int old_capi_manufacturer(unsigned int cmd, void __user *data)
1008{
1009 avmb1_loadandconfigdef ldef;
1010 avmb1_extcarddef cdef;
1011 avmb1_resetdef rdef;
1012 capicardparams cparams;
Jan Kiszka52253032010-02-08 10:12:10 +00001013 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 struct capi_driver *driver = NULL;
1015 capiloaddata ldata;
1016 struct list_head *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 int retval;
1018
1019 switch (cmd) {
1020 case AVMB1_ADDCARD:
1021 case AVMB1_ADDCARD_WITH_TYPE:
1022 if (cmd == AVMB1_ADDCARD) {
1023 if ((retval = copy_from_user(&cdef, data,
1024 sizeof(avmb1_carddef))))
1025 return retval;
1026 cdef.cardtype = AVM_CARDTYPE_B1;
1027 } else {
1028 if ((retval = copy_from_user(&cdef, data,
1029 sizeof(avmb1_extcarddef))))
1030 return retval;
1031 }
1032 cparams.port = cdef.port;
1033 cparams.irq = cdef.irq;
1034 cparams.cardnr = cdef.cardnr;
1035
Jan Kiszka9717fb82010-02-08 10:12:11 +00001036 mutex_lock(&capi_drivers_lock);
1037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 switch (cdef.cardtype) {
1039 case AVM_CARDTYPE_B1:
1040 list_for_each(l, &capi_drivers) {
1041 driver = list_entry(l, struct capi_driver, list);
1042 if (strcmp(driver->name, "b1isa") == 0)
1043 break;
1044 }
1045 break;
1046 case AVM_CARDTYPE_T1:
1047 list_for_each(l, &capi_drivers) {
1048 driver = list_entry(l, struct capi_driver, list);
1049 if (strcmp(driver->name, "t1isa") == 0)
1050 break;
1051 }
1052 break;
1053 default:
1054 driver = NULL;
1055 break;
1056 }
1057 if (!driver) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 printk(KERN_ERR "kcapi: driver not loaded.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +00001059 retval = -EIO;
1060 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 printk(KERN_ERR "kcapi: driver has no add card function.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +00001062 retval = -EIO;
1063 } else
1064 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Jan Kiszka9717fb82010-02-08 10:12:11 +00001066 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return retval;
1068
1069 case AVMB1_LOAD:
1070 case AVMB1_LOAD_AND_CONFIG:
1071
1072 if (cmd == AVMB1_LOAD) {
1073 if (copy_from_user(&ldef, data,
1074 sizeof(avmb1_loaddef)))
1075 return -EFAULT;
1076 ldef.t4config.len = 0;
1077 ldef.t4config.data = NULL;
1078 } else {
1079 if (copy_from_user(&ldef, data,
1080 sizeof(avmb1_loadandconfigdef)))
1081 return -EFAULT;
1082 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001083
1084 mutex_lock(&capi_controller_lock);
1085
Jan Kiszka52253032010-02-08 10:12:10 +00001086 ctr = get_capi_ctr_by_nr(ldef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001087 if (!ctr) {
1088 retval = -EINVAL;
1089 goto load_unlock_out;
1090 }
1091
Jan Kiszka52253032010-02-08 10:12:10 +00001092 if (ctr->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 printk(KERN_DEBUG "kcapi: load: no load function\n");
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001094 retval = -ESRCH;
1095 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097
1098 if (ldef.t4file.len <= 0) {
1099 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001100 retval = -EINVAL;
1101 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001103 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001105 retval = -EINVAL;
1106 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 }
1108
1109 ldata.firmware.user = 1;
1110 ldata.firmware.data = ldef.t4file.data;
1111 ldata.firmware.len = ldef.t4file.len;
1112 ldata.configuration.user = 1;
1113 ldata.configuration.data = ldef.t4config.data;
1114 ldata.configuration.len = ldef.t4config.len;
1115
Jan Kiszka52253032010-02-08 10:12:10 +00001116 if (ctr->state != CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001118 retval = -EBUSY;
1119 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 }
Jan Kiszka52253032010-02-08 10:12:10 +00001121 ctr->state = CAPI_CTR_LOADING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
Jan Kiszka52253032010-02-08 10:12:10 +00001123 retval = ctr->load_firmware(ctr, &ldata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (retval) {
Jan Kiszka52253032010-02-08 10:12:10 +00001125 ctr->state = CAPI_CTR_DETECTED;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001126 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001129 retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001131load_unlock_out:
1132 mutex_unlock(&capi_controller_lock);
1133 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 case AVMB1_RESETCARD:
1136 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1137 return -EFAULT;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001138
1139 retval = 0;
1140
1141 mutex_lock(&capi_controller_lock);
1142
Jan Kiszka52253032010-02-08 10:12:10 +00001143 ctr = get_capi_ctr_by_nr(rdef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001144 if (!ctr) {
1145 retval = -ESRCH;
1146 goto reset_unlock_out;
1147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Jan Kiszka52253032010-02-08 10:12:10 +00001149 if (ctr->state == CAPI_CTR_DETECTED)
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001150 goto reset_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Jan Kiszka52253032010-02-08 10:12:10 +00001152 ctr->reset_ctr(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001154 retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001156reset_unlock_out:
1157 mutex_unlock(&capi_controller_lock);
1158 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 return -EINVAL;
1161}
1162#endif
1163
Tilman Schmidt554f2002009-04-23 02:24:21 +00001164/**
1165 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1166 * @cmd: command.
1167 * @data: parameter.
1168 *
1169 * Perform manufacturer specific command.
1170 * Return value: CAPI result code
1171 */
1172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173int capi20_manufacturer(unsigned int cmd, void __user *data)
1174{
Jan Kiszka52253032010-02-08 10:12:10 +00001175 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001176 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001179#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 case AVMB1_LOAD:
1181 case AVMB1_LOAD_AND_CONFIG:
1182 case AVMB1_RESETCARD:
1183 case AVMB1_GET_CARDINFO:
1184 case AVMB1_REMOVECARD:
1185 return old_capi_manufacturer(cmd, data);
1186#endif
1187 case KCAPI_CMD_TRACE:
1188 {
1189 kcapi_flagdef fdef;
1190
1191 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1192 return -EFAULT;
1193
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001194 mutex_lock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001196 ctr = get_capi_ctr_by_nr(fdef.contr);
1197 if (ctr) {
1198 ctr->traceflag = fdef.flag;
1199 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
1200 ctr->cnr, ctr->traceflag);
1201 retval = 0;
1202 } else
1203 retval = -ESRCH;
1204
1205 mutex_unlock(&capi_controller_lock);
1206
1207 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 }
1209 case KCAPI_CMD_ADDCARD:
1210 {
1211 struct list_head *l;
1212 struct capi_driver *driver = NULL;
1213 capicardparams cparams;
1214 kcapi_carddef cdef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
1216 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1217 return retval;
1218
1219 cparams.port = cdef.port;
1220 cparams.irq = cdef.irq;
1221 cparams.membase = cdef.membase;
1222 cparams.cardnr = cdef.cardnr;
1223 cparams.cardtype = 0;
1224 cdef.driver[sizeof(cdef.driver)-1] = 0;
1225
Jan Kiszka9717fb82010-02-08 10:12:11 +00001226 mutex_lock(&capi_drivers_lock);
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 list_for_each(l, &capi_drivers) {
1229 driver = list_entry(l, struct capi_driver, list);
1230 if (strcmp(driver->name, cdef.driver) == 0)
1231 break;
1232 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001233 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1235 cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001236 retval = -ESRCH;
1237 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001239 retval = -EIO;
1240 } else
1241 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jan Kiszka9717fb82010-02-08 10:12:11 +00001243 mutex_unlock(&capi_drivers_lock);
1244 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
1246
1247 default:
1248 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1249 cmd);
1250 break;
1251
1252 }
1253 return -EINVAL;
1254}
1255
1256EXPORT_SYMBOL(capi20_manufacturer);
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258/* ------------------------------------------------------------- */
1259/* -------- Init & Cleanup ------------------------------------- */
1260/* ------------------------------------------------------------- */
1261
1262/*
1263 * init / exit functions
1264 */
1265
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001266static struct notifier_block capictr_nb = {
1267 .notifier_call = notify_handler,
1268 .priority = INT_MAX,
1269};
1270
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271static int __init kcapi_init(void)
1272{
Jan Kiszka88549d62010-02-08 10:12:09 +00001273 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001275 register_capictr_notifier(&capictr_nb);
1276
Jan Kiszka88549d62010-02-08 10:12:09 +00001277 err = cdebug_init();
1278 if (!err)
1279 kcapi_proc_init();
1280 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281}
1282
1283static void __exit kcapi_exit(void)
1284{
1285 kcapi_proc_exit();
1286
1287 /* make sure all notifiers are finished */
1288 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001289 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290}
1291
1292module_init(kcapi_init);
1293module_exit(kcapi_exit);