blob: ce9b05b9e93a93ab6974ddf714a28fa3867299b3 [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));
Jan Kiszkac6af0432010-02-08 10:12:43 +0000780 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
781 return CAPI_REGNOTINSTALLED;
Jan Kiszka52253032010-02-08 10:12:10 +0000782 if (ctr->blocked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return CAPI_SENDQUEUEFULL;
784
785 cmd = CAPIMSG_COMMAND(skb->data);
786 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
787
788 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
Jan Kiszka52253032010-02-08 10:12:10 +0000789 ctr->nsentdatapkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 ap->nsentdatapkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000791 if (ctr->traceflag > 2)
792 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000794 ctr->nsentctlpkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 ap->nsentctlpkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000796 if (ctr->traceflag)
797 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
Jan Kiszka52253032010-02-08 10:12:10 +0000799 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (showctl & 2) {
801 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800802 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 CAPIMSG_CONTROLLER(skb->data),
804 CAPIMSG_APPID(skb->data),
805 capi_cmd2str(cmd, subcmd),
806 CAPIMSG_LEN(skb->data));
807 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800808 _cdebbuf *cdb = capi_message2str(skb->data);
809 if (cdb) {
810 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
811 CAPIMSG_CONTROLLER(skb->data),
812 cdb->buf);
813 cdebbuf_free(cdb);
814 } else
815 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
816 CAPIMSG_CONTROLLER(skb->data),
817 CAPIMSG_APPID(skb->data),
818 capi_cmd2str(cmd, subcmd),
819 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
Jan Kiszka52253032010-02-08 10:12:10 +0000822 return ctr->send_message(ctr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823}
824
825EXPORT_SYMBOL(capi20_put_message);
826
Tilman Schmidt554f2002009-04-23 02:24:21 +0000827/**
828 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
829 * @contr: controller number.
830 * @buf: result buffer (64 bytes).
831 *
832 * Retrieve information about the manufacturer of the specified ISDN controller
833 * or (for @contr == 0) the driver itself.
834 * Return value: CAPI result code
835 */
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837u16 capi20_get_manufacturer(u32 contr, u8 *buf)
838{
Jan Kiszka52253032010-02-08 10:12:10 +0000839 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000840 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
842 if (contr == 0) {
843 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
844 return CAPI_NOERROR;
845 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000846
847 mutex_lock(&capi_controller_lock);
848
Jan Kiszka52253032010-02-08 10:12:10 +0000849 ctr = get_capi_ctr_by_nr(contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000850 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
851 strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
852 ret = CAPI_NOERROR;
853 } else
854 ret = CAPI_REGNOTINSTALLED;
855
856 mutex_unlock(&capi_controller_lock);
857 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
860EXPORT_SYMBOL(capi20_get_manufacturer);
861
Tilman Schmidt554f2002009-04-23 02:24:21 +0000862/**
863 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
864 * @contr: controller number.
865 * @verp: result structure.
866 *
867 * Retrieve version information for the specified ISDN controller
868 * or (for @contr == 0) the driver itself.
869 * Return value: CAPI result code
870 */
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872u16 capi20_get_version(u32 contr, struct capi_version *verp)
873{
Jan Kiszka52253032010-02-08 10:12:10 +0000874 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000875 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 if (contr == 0) {
878 *verp = driver_version;
879 return CAPI_NOERROR;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000882 mutex_lock(&capi_controller_lock);
883
884 ctr = get_capi_ctr_by_nr(contr);
885 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
886 memcpy(verp, &ctr->version, sizeof(capi_version));
887 ret = CAPI_NOERROR;
888 } else
889 ret = CAPI_REGNOTINSTALLED;
890
891 mutex_unlock(&capi_controller_lock);
892 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
895EXPORT_SYMBOL(capi20_get_version);
896
Tilman Schmidt554f2002009-04-23 02:24:21 +0000897/**
898 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
899 * @contr: controller number.
900 * @serial: result buffer (8 bytes).
901 *
902 * Retrieve the serial number of the specified ISDN controller
903 * or (for @contr == 0) the driver itself.
904 * Return value: CAPI result code
905 */
906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907u16 capi20_get_serial(u32 contr, u8 *serial)
908{
Jan Kiszka52253032010-02-08 10:12:10 +0000909 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000910 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 if (contr == 0) {
913 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
914 return CAPI_NOERROR;
915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000917 mutex_lock(&capi_controller_lock);
918
919 ctr = get_capi_ctr_by_nr(contr);
920 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
921 strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
922 ret = CAPI_NOERROR;
923 } else
924 ret = CAPI_REGNOTINSTALLED;
925
926 mutex_unlock(&capi_controller_lock);
927 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928}
929
930EXPORT_SYMBOL(capi20_get_serial);
931
Tilman Schmidt554f2002009-04-23 02:24:21 +0000932/**
933 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
934 * @contr: controller number.
935 * @profp: result structure.
936 *
937 * Retrieve capability information for the specified ISDN controller
938 * or (for @contr == 0) the number of installed controllers.
939 * Return value: CAPI result code
940 */
941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
943{
Jan Kiszka52253032010-02-08 10:12:10 +0000944 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000945 u16 ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 if (contr == 0) {
Jan Kiszka52253032010-02-08 10:12:10 +0000948 profp->ncontroller = ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return CAPI_NOERROR;
950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000952 mutex_lock(&capi_controller_lock);
953
954 ctr = get_capi_ctr_by_nr(contr);
955 if (ctr && ctr->state == CAPI_CTR_RUNNING) {
956 memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
957 ret = CAPI_NOERROR;
958 } else
959 ret = CAPI_REGNOTINSTALLED;
960
961 mutex_unlock(&capi_controller_lock);
962 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963}
964
965EXPORT_SYMBOL(capi20_get_profile);
966
Jan Kiszka0ca3a012010-02-08 10:12:14 +0000967/* Must be called with capi_controller_lock held. */
968static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state)
969{
970 DEFINE_WAIT(wait);
971 int retval = 0;
972
973 ctr = capi_ctr_get(ctr);
974 if (!ctr)
975 return -ESRCH;
976
977 for (;;) {
978 prepare_to_wait(&ctr->state_wait_queue, &wait,
979 TASK_INTERRUPTIBLE);
980
981 if (ctr->state == state)
982 break;
983 if (ctr->state == CAPI_CTR_DETACHED) {
984 retval = -ESRCH;
985 break;
986 }
987 if (signal_pending(current)) {
988 retval = -EINTR;
989 break;
990 }
991
992 mutex_unlock(&capi_controller_lock);
993 schedule();
994 mutex_lock(&capi_controller_lock);
995 }
996 finish_wait(&ctr->state_wait_queue, &wait);
997
998 capi_ctr_put(ctr);
999
1000 return retval;
1001}
1002
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001003#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004static int old_capi_manufacturer(unsigned int cmd, void __user *data)
1005{
1006 avmb1_loadandconfigdef ldef;
1007 avmb1_extcarddef cdef;
1008 avmb1_resetdef rdef;
1009 capicardparams cparams;
Jan Kiszka52253032010-02-08 10:12:10 +00001010 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 struct capi_driver *driver = NULL;
1012 capiloaddata ldata;
1013 struct list_head *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 int retval;
1015
1016 switch (cmd) {
1017 case AVMB1_ADDCARD:
1018 case AVMB1_ADDCARD_WITH_TYPE:
1019 if (cmd == AVMB1_ADDCARD) {
1020 if ((retval = copy_from_user(&cdef, data,
1021 sizeof(avmb1_carddef))))
1022 return retval;
1023 cdef.cardtype = AVM_CARDTYPE_B1;
1024 } else {
1025 if ((retval = copy_from_user(&cdef, data,
1026 sizeof(avmb1_extcarddef))))
1027 return retval;
1028 }
1029 cparams.port = cdef.port;
1030 cparams.irq = cdef.irq;
1031 cparams.cardnr = cdef.cardnr;
1032
Jan Kiszka9717fb82010-02-08 10:12:11 +00001033 mutex_lock(&capi_drivers_lock);
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 switch (cdef.cardtype) {
1036 case AVM_CARDTYPE_B1:
1037 list_for_each(l, &capi_drivers) {
1038 driver = list_entry(l, struct capi_driver, list);
1039 if (strcmp(driver->name, "b1isa") == 0)
1040 break;
1041 }
1042 break;
1043 case AVM_CARDTYPE_T1:
1044 list_for_each(l, &capi_drivers) {
1045 driver = list_entry(l, struct capi_driver, list);
1046 if (strcmp(driver->name, "t1isa") == 0)
1047 break;
1048 }
1049 break;
1050 default:
1051 driver = NULL;
1052 break;
1053 }
1054 if (!driver) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 printk(KERN_ERR "kcapi: driver not loaded.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +00001056 retval = -EIO;
1057 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 printk(KERN_ERR "kcapi: driver has no add card function.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +00001059 retval = -EIO;
1060 } else
1061 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Jan Kiszka9717fb82010-02-08 10:12:11 +00001063 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return retval;
1065
1066 case AVMB1_LOAD:
1067 case AVMB1_LOAD_AND_CONFIG:
1068
1069 if (cmd == AVMB1_LOAD) {
1070 if (copy_from_user(&ldef, data,
1071 sizeof(avmb1_loaddef)))
1072 return -EFAULT;
1073 ldef.t4config.len = 0;
1074 ldef.t4config.data = NULL;
1075 } else {
1076 if (copy_from_user(&ldef, data,
1077 sizeof(avmb1_loadandconfigdef)))
1078 return -EFAULT;
1079 }
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001080
1081 mutex_lock(&capi_controller_lock);
1082
Jan Kiszka52253032010-02-08 10:12:10 +00001083 ctr = get_capi_ctr_by_nr(ldef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001084 if (!ctr) {
1085 retval = -EINVAL;
1086 goto load_unlock_out;
1087 }
1088
Jan Kiszka52253032010-02-08 10:12:10 +00001089 if (ctr->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 printk(KERN_DEBUG "kcapi: load: no load function\n");
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001091 retval = -ESRCH;
1092 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
1094
1095 if (ldef.t4file.len <= 0) {
1096 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001097 retval = -EINVAL;
1098 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001100 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001102 retval = -EINVAL;
1103 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105
1106 ldata.firmware.user = 1;
1107 ldata.firmware.data = ldef.t4file.data;
1108 ldata.firmware.len = ldef.t4file.len;
1109 ldata.configuration.user = 1;
1110 ldata.configuration.data = ldef.t4config.data;
1111 ldata.configuration.len = ldef.t4config.len;
1112
Jan Kiszka52253032010-02-08 10:12:10 +00001113 if (ctr->state != CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001115 retval = -EBUSY;
1116 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
Jan Kiszka52253032010-02-08 10:12:10 +00001118 ctr->state = CAPI_CTR_LOADING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Jan Kiszka52253032010-02-08 10:12:10 +00001120 retval = ctr->load_firmware(ctr, &ldata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (retval) {
Jan Kiszka52253032010-02-08 10:12:10 +00001122 ctr->state = CAPI_CTR_DETECTED;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001123 goto load_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
1125
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001126 retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001128load_unlock_out:
1129 mutex_unlock(&capi_controller_lock);
1130 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 case AVMB1_RESETCARD:
1133 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1134 return -EFAULT;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001135
1136 retval = 0;
1137
1138 mutex_lock(&capi_controller_lock);
1139
Jan Kiszka52253032010-02-08 10:12:10 +00001140 ctr = get_capi_ctr_by_nr(rdef.contr);
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001141 if (!ctr) {
1142 retval = -ESRCH;
1143 goto reset_unlock_out;
1144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Jan Kiszka52253032010-02-08 10:12:10 +00001146 if (ctr->state == CAPI_CTR_DETECTED)
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001147 goto reset_unlock_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Jan Kiszka52253032010-02-08 10:12:10 +00001149 ctr->reset_ctr(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001151 retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001153reset_unlock_out:
1154 mutex_unlock(&capi_controller_lock);
1155 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
1157 return -EINVAL;
1158}
1159#endif
1160
Tilman Schmidt554f2002009-04-23 02:24:21 +00001161/**
1162 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1163 * @cmd: command.
1164 * @data: parameter.
1165 *
1166 * Perform manufacturer specific command.
1167 * Return value: CAPI result code
1168 */
1169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170int capi20_manufacturer(unsigned int cmd, void __user *data)
1171{
Jan Kiszka52253032010-02-08 10:12:10 +00001172 struct capi_ctr *ctr;
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001173 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001176#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 case AVMB1_LOAD:
1178 case AVMB1_LOAD_AND_CONFIG:
1179 case AVMB1_RESETCARD:
1180 case AVMB1_GET_CARDINFO:
1181 case AVMB1_REMOVECARD:
1182 return old_capi_manufacturer(cmd, data);
1183#endif
1184 case KCAPI_CMD_TRACE:
1185 {
1186 kcapi_flagdef fdef;
1187
1188 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1189 return -EFAULT;
1190
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001191 mutex_lock(&capi_controller_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
Jan Kiszka0ca3a012010-02-08 10:12:14 +00001193 ctr = get_capi_ctr_by_nr(fdef.contr);
1194 if (ctr) {
1195 ctr->traceflag = fdef.flag;
1196 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
1197 ctr->cnr, ctr->traceflag);
1198 retval = 0;
1199 } else
1200 retval = -ESRCH;
1201
1202 mutex_unlock(&capi_controller_lock);
1203
1204 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
1206 case KCAPI_CMD_ADDCARD:
1207 {
1208 struct list_head *l;
1209 struct capi_driver *driver = NULL;
1210 capicardparams cparams;
1211 kcapi_carddef cdef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1214 return retval;
1215
1216 cparams.port = cdef.port;
1217 cparams.irq = cdef.irq;
1218 cparams.membase = cdef.membase;
1219 cparams.cardnr = cdef.cardnr;
1220 cparams.cardtype = 0;
1221 cdef.driver[sizeof(cdef.driver)-1] = 0;
1222
Jan Kiszka9717fb82010-02-08 10:12:11 +00001223 mutex_lock(&capi_drivers_lock);
1224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 list_for_each(l, &capi_drivers) {
1226 driver = list_entry(l, struct capi_driver, list);
1227 if (strcmp(driver->name, cdef.driver) == 0)
1228 break;
1229 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001230 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1232 cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001233 retval = -ESRCH;
1234 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001236 retval = -EIO;
1237 } else
1238 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Jan Kiszka9717fb82010-02-08 10:12:11 +00001240 mutex_unlock(&capi_drivers_lock);
1241 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243
1244 default:
1245 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1246 cmd);
1247 break;
1248
1249 }
1250 return -EINVAL;
1251}
1252
1253EXPORT_SYMBOL(capi20_manufacturer);
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255/* ------------------------------------------------------------- */
1256/* -------- Init & Cleanup ------------------------------------- */
1257/* ------------------------------------------------------------- */
1258
1259/*
1260 * init / exit functions
1261 */
1262
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001263static struct notifier_block capictr_nb = {
1264 .notifier_call = notify_handler,
1265 .priority = INT_MAX,
1266};
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268static int __init kcapi_init(void)
1269{
Jan Kiszka88549d62010-02-08 10:12:09 +00001270 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001272 register_capictr_notifier(&capictr_nb);
1273
Jan Kiszka88549d62010-02-08 10:12:09 +00001274 err = cdebug_init();
1275 if (!err)
1276 kcapi_proc_init();
1277 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278}
1279
1280static void __exit kcapi_exit(void)
1281{
1282 kcapi_proc_exit();
1283
1284 /* make sure all notifiers are finished */
1285 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001286 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287}
1288
1289module_init(kcapi_init);
1290module_exit(kcapi_exit);