blob: c46964fc17c79656adc9cc0f955652456b297992 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static int showcapimsgs = 0;
39
40MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
41MODULE_AUTHOR("Carsten Paeth");
42MODULE_LICENSE("GPL");
43module_param(showcapimsgs, uint, 0);
44
45/* ------------------------------------------------------------- */
46
47struct capi_notifier {
48 struct work_struct work;
49 unsigned int cmd;
50 u32 controller;
51 u16 applid;
52 u32 ncci;
53};
54
55/* ------------------------------------------------------------- */
56
57static struct capi_version driver_version = {2, 0, 1, 1<<4};
58static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
59static char capi_manufakturer[64] = "AVM Berlin";
60
61#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
62
63LIST_HEAD(capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +000064DEFINE_MUTEX(capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66static DEFINE_RWLOCK(application_lock);
Arjan van de Ven9cdf1822006-03-23 03:00:21 -080067static DEFINE_MUTEX(controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69struct capi20_appl *capi_applications[CAPI_MAXAPPL];
Jan Kiszka52253032010-02-08 10:12:10 +000070struct capi_ctr *capi_controller[CAPI_MAXCONTR];
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jan Kiszka52253032010-02-08 10:12:10 +000072static int ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* -------- 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
105 return capi_applications[applid - 1];
106}
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
168/* -------- KCI_CONTRUP --------------------------------------- */
169
170static void notify_up(u32 contr)
171{
Jan Kiszka52253032010-02-08 10:12:10 +0000172 struct capi_ctr *ctr = get_capi_ctr_by_nr(contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 struct capi20_appl *ap;
174 u16 applid;
175
176 if (showcapimsgs & 1) {
177 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
178 }
Jan Kiszka52253032010-02-08 10:12:10 +0000179 if (!ctr) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700180 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return;
182 }
183 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
184 ap = get_capi_appl_by_nr(applid);
185 if (!ap || ap->release_in_progress) continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000186 register_appl(ctr, applid, &ap->rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 if (ap->callback && !ap->release_in_progress)
Jan Kiszka52253032010-02-08 10:12:10 +0000188 ap->callback(KCI_CONTRUP, contr, &ctr->profile);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
190}
191
192/* -------- KCI_CONTRDOWN ------------------------------------- */
193
194static void notify_down(u32 contr)
195{
196 struct capi20_appl *ap;
197 u16 applid;
198
199 if (showcapimsgs & 1) {
200 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
201 }
202
203 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
204 ap = get_capi_appl_by_nr(applid);
205 if (ap && ap->callback && !ap->release_in_progress)
206 ap->callback(KCI_CONTRDOWN, contr, NULL);
207 }
208}
209
David Howellsc4028952006-11-22 14:57:56 +0000210static void notify_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
David Howellsc4028952006-11-22 14:57:56 +0000212 struct capi_notifier *np =
213 container_of(work, struct capi_notifier, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 switch (np->cmd) {
216 case KCI_CONTRUP:
217 notify_up(np->controller);
218 break;
219 case KCI_CONTRDOWN:
220 notify_down(np->controller);
221 break;
222 }
223
224 kfree(np);
225}
226
227/*
228 * The notifier will result in adding/deleteing of devices. Devices can
229 * only removed in user process, not in bh.
230 */
231static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
232{
233 struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
234
235 if (!np)
236 return -ENOMEM;
237
David Howellsc4028952006-11-22 14:57:56 +0000238 INIT_WORK(&np->work, notify_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 np->cmd = cmd;
240 np->controller = controller;
241 np->applid = applid;
242 np->ncci = ncci;
243
244 schedule_work(&np->work);
245 return 0;
246}
247
248
249/* -------- Receiver ------------------------------------------ */
250
David Howellsc4028952006-11-22 14:57:56 +0000251static void recv_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
253 struct sk_buff *skb;
David Howellsc4028952006-11-22 14:57:56 +0000254 struct capi20_appl *ap =
255 container_of(work, struct capi20_appl, recv_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if ((!ap) || (ap->release_in_progress))
258 return;
259
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700260 mutex_lock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 while ((skb = skb_dequeue(&ap->recv_queue))) {
262 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
263 ap->nrecvdatapkt++;
264 else
265 ap->nrecvctlpkt++;
266
267 ap->recv_message(ap, skb);
268 }
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700269 mutex_unlock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
Tilman Schmidt554f2002009-04-23 02:24:21 +0000272/**
273 * capi_ctr_handle_message() - handle incoming CAPI message
Jan Kiszka52253032010-02-08 10:12:10 +0000274 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000275 * @appl: application ID.
276 * @skb: message.
277 *
278 * Called by hardware driver to pass a CAPI message to the application.
279 */
280
Jan Kiszka52253032010-02-08 10:12:10 +0000281void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
282 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
284 struct capi20_appl *ap;
285 int showctl = 0;
286 u8 cmd, subcmd;
287 unsigned long flags;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800288 _cdebbuf *cdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Jan Kiszka52253032010-02-08 10:12:10 +0000290 if (ctr->state != CAPI_CTR_RUNNING) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800291 cdb = capi_message2str(skb->data);
292 if (cdb) {
293 printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
Jan Kiszka52253032010-02-08 10:12:10 +0000294 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800295 cdebbuf_free(cdb);
296 } else
297 printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000298 ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 goto error;
300 }
301
302 cmd = CAPIMSG_COMMAND(skb->data);
303 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
304 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
Jan Kiszka52253032010-02-08 10:12:10 +0000305 ctr->nrecvdatapkt++;
306 if (ctr->traceflag > 2)
307 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000309 ctr->nrecvctlpkt++;
310 if (ctr->traceflag)
311 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
Jan Kiszka52253032010-02-08 10:12:10 +0000313 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (showctl & 2) {
315 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800316 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000317 ctr->cnr, CAPIMSG_APPID(skb->data),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 capi_cmd2str(cmd, subcmd),
319 CAPIMSG_LEN(skb->data));
320 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800321 cdb = capi_message2str(skb->data);
322 if (cdb) {
323 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000324 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800325 cdebbuf_free(cdb);
326 } else
327 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000328 ctr->cnr, CAPIMSG_APPID(skb->data),
Karsten Keil17f0cd22007-02-28 20:13:50 -0800329 capi_cmd2str(cmd, subcmd),
330 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332
333 }
334
335 read_lock_irqsave(&application_lock, flags);
336 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
337 if ((!ap) || (ap->release_in_progress)) {
338 read_unlock_irqrestore(&application_lock, flags);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800339 cdb = capi_message2str(skb->data);
340 if (cdb) {
341 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
342 CAPIMSG_APPID(skb->data), cdb->buf);
343 cdebbuf_free(cdb);
344 } else
345 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
346 CAPIMSG_APPID(skb->data),
347 capi_cmd2str(cmd, subcmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 goto error;
349 }
350 skb_queue_tail(&ap->recv_queue, skb);
351 schedule_work(&ap->recv_work);
352 read_unlock_irqrestore(&application_lock, flags);
353
354 return;
355
356error:
357 kfree_skb(skb);
358}
359
360EXPORT_SYMBOL(capi_ctr_handle_message);
361
Tilman Schmidt554f2002009-04-23 02:24:21 +0000362/**
363 * capi_ctr_ready() - signal CAPI controller ready
Jan Kiszka52253032010-02-08 10:12:10 +0000364 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000365 *
366 * Called by hardware driver to signal that the controller is up and running.
367 */
368
Jan Kiszka52253032010-02-08 10:12:10 +0000369void capi_ctr_ready(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{
Jan Kiszka52253032010-02-08 10:12:10 +0000371 ctr->state = CAPI_CTR_RUNNING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Jan Kiszka52253032010-02-08 10:12:10 +0000373 printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
374 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Jan Kiszka52253032010-02-08 10:12:10 +0000376 notify_push(KCI_CONTRUP, ctr->cnr, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
379EXPORT_SYMBOL(capi_ctr_ready);
380
Tilman Schmidt554f2002009-04-23 02:24:21 +0000381/**
Tilman Schmidt4e329972009-06-07 09:09:23 +0000382 * capi_ctr_down() - signal CAPI controller not ready
Jan Kiszka52253032010-02-08 10:12:10 +0000383 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000384 *
385 * Called by hardware driver to signal that the controller is down and
386 * unavailable for use.
387 */
388
Jan Kiszka52253032010-02-08 10:12:10 +0000389void capi_ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
391 u16 appl;
392
393 DBG("");
394
Jan Kiszka52253032010-02-08 10:12:10 +0000395 if (ctr->state == CAPI_CTR_DETECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return;
397
Jan Kiszka52253032010-02-08 10:12:10 +0000398 ctr->state = CAPI_CTR_DETECTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Jan Kiszka52253032010-02-08 10:12:10 +0000400 memset(ctr->manu, 0, sizeof(ctr->manu));
401 memset(&ctr->version, 0, sizeof(ctr->version));
402 memset(&ctr->profile, 0, sizeof(ctr->profile));
403 memset(ctr->serial, 0, sizeof(ctr->serial));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
406 struct capi20_appl *ap = get_capi_appl_by_nr(appl);
407 if (!ap || ap->release_in_progress)
408 continue;
409
Jan Kiszka52253032010-02-08 10:12:10 +0000410 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
412
Jan Kiszka52253032010-02-08 10:12:10 +0000413 printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Jan Kiszka52253032010-02-08 10:12:10 +0000415 notify_push(KCI_CONTRDOWN, ctr->cnr, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
Tilman Schmidt4e329972009-06-07 09:09:23 +0000418EXPORT_SYMBOL(capi_ctr_down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Tilman Schmidt554f2002009-04-23 02:24:21 +0000420/**
421 * capi_ctr_suspend_output() - suspend controller
Jan Kiszka52253032010-02-08 10:12:10 +0000422 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000423 *
424 * Called by hardware driver to stop data flow.
425 */
426
Jan Kiszka52253032010-02-08 10:12:10 +0000427void capi_ctr_suspend_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Jan Kiszka52253032010-02-08 10:12:10 +0000429 if (!ctr->blocked) {
430 printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
431 ctr->cnr);
432 ctr->blocked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
434}
435
436EXPORT_SYMBOL(capi_ctr_suspend_output);
437
Tilman Schmidt554f2002009-04-23 02:24:21 +0000438/**
439 * capi_ctr_resume_output() - resume controller
Jan Kiszka52253032010-02-08 10:12:10 +0000440 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000441 *
442 * Called by hardware driver to resume data flow.
443 */
444
Jan Kiszka52253032010-02-08 10:12:10 +0000445void capi_ctr_resume_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Jan Kiszka52253032010-02-08 10:12:10 +0000447 if (ctr->blocked) {
448 printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
449 ctr->cnr);
450 ctr->blocked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 }
452}
453
454EXPORT_SYMBOL(capi_ctr_resume_output);
455
456/* ------------------------------------------------------------- */
457
Tilman Schmidt554f2002009-04-23 02:24:21 +0000458/**
459 * attach_capi_ctr() - register CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000460 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000461 *
462 * Called by hardware driver to register a controller with the CAPI subsystem.
463 * Return value: 0 on success, error code < 0 on error
464 */
465
Jan Kiszka52253032010-02-08 10:12:10 +0000466int attach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
468 int i;
469
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800470 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000473 if (!capi_controller[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 break;
475 }
476 if (i == CAPI_MAXCONTR) {
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800477 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 printk(KERN_ERR "kcapi: out of controller slots\n");
479 return -EBUSY;
480 }
Jan Kiszka52253032010-02-08 10:12:10 +0000481 capi_controller[i] = ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800483 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Jan Kiszka52253032010-02-08 10:12:10 +0000485 ctr->nrecvctlpkt = 0;
486 ctr->nrecvdatapkt = 0;
487 ctr->nsentctlpkt = 0;
488 ctr->nsentdatapkt = 0;
489 ctr->cnr = i + 1;
490 ctr->state = CAPI_CTR_DETECTED;
491 ctr->blocked = 0;
492 ctr->traceflag = showcapimsgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Jan Kiszka52253032010-02-08 10:12:10 +0000494 sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
495 ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Jan Kiszka52253032010-02-08 10:12:10 +0000497 ncontrollers++;
498 printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
499 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return 0;
501}
502
503EXPORT_SYMBOL(attach_capi_ctr);
504
Tilman Schmidt554f2002009-04-23 02:24:21 +0000505/**
506 * detach_capi_ctr() - unregister CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000507 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000508 *
509 * Called by hardware driver to remove the registration of a controller
510 * with the CAPI subsystem.
511 * Return value: 0 on success, error code < 0 on error
512 */
513
Jan Kiszka52253032010-02-08 10:12:10 +0000514int detach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
Jan Kiszka52253032010-02-08 10:12:10 +0000516 if (ctr->state != CAPI_CTR_DETECTED)
517 capi_ctr_down(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Jan Kiszka52253032010-02-08 10:12:10 +0000519 ncontrollers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Jan Kiszka52253032010-02-08 10:12:10 +0000521 if (ctr->procent) {
522 remove_proc_entry(ctr->procfn, NULL);
523 ctr->procent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Jan Kiszka52253032010-02-08 10:12:10 +0000525 capi_controller[ctr->cnr - 1] = NULL;
526 printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
527 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529 return 0;
530}
531
532EXPORT_SYMBOL(detach_capi_ctr);
533
Tilman Schmidt554f2002009-04-23 02:24:21 +0000534/**
535 * register_capi_driver() - register CAPI driver
536 * @driver: driver descriptor structure.
537 *
538 * Called by hardware driver to register itself with the CAPI subsystem.
539 */
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541void register_capi_driver(struct capi_driver *driver)
542{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000543 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 list_add_tail(&driver->list, &capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000545 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546}
547
548EXPORT_SYMBOL(register_capi_driver);
549
Tilman Schmidt554f2002009-04-23 02:24:21 +0000550/**
551 * unregister_capi_driver() - unregister CAPI driver
552 * @driver: driver descriptor structure.
553 *
554 * Called by hardware driver to unregister itself from the CAPI subsystem.
555 */
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557void unregister_capi_driver(struct capi_driver *driver)
558{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000559 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 list_del(&driver->list);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000561 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
564EXPORT_SYMBOL(unregister_capi_driver);
565
566/* ------------------------------------------------------------- */
567/* -------- CAPI2.0 Interface ---------------------------------- */
568/* ------------------------------------------------------------- */
569
Tilman Schmidt554f2002009-04-23 02:24:21 +0000570/**
571 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
572 *
573 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
574 * is ready for use, CAPI_REGNOTINSTALLED otherwise)
575 */
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577u16 capi20_isinstalled(void)
578{
579 int i;
580 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000581 if (capi_controller[i] &&
582 capi_controller[i]->state == CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 return CAPI_NOERROR;
584 }
585 return CAPI_REGNOTINSTALLED;
586}
587
588EXPORT_SYMBOL(capi20_isinstalled);
589
Tilman Schmidt554f2002009-04-23 02:24:21 +0000590/**
591 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
592 * @ap: CAPI application descriptor structure.
593 *
594 * Register an application's presence with CAPI.
595 * A unique application ID is assigned and stored in @ap->applid.
596 * After this function returns successfully, the message receive
597 * callback function @ap->recv_message() may be called at any time
598 * until capi20_release() has been called for the same @ap.
599 * Return value: CAPI result code
600 */
601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602u16 capi20_register(struct capi20_appl *ap)
603{
604 int i;
605 u16 applid;
606 unsigned long flags;
607
608 DBG("");
609
610 if (ap->rparam.datablklen < 128)
611 return CAPI_LOGBLKSIZETOSMALL;
612
613 write_lock_irqsave(&application_lock, flags);
614
615 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
616 if (capi_applications[applid - 1] == NULL)
617 break;
618 }
619 if (applid > CAPI_MAXAPPL) {
620 write_unlock_irqrestore(&application_lock, flags);
621 return CAPI_TOOMANYAPPLS;
622 }
623
624 ap->applid = applid;
625 capi_applications[applid - 1] = ap;
626
627 ap->nrecvctlpkt = 0;
628 ap->nrecvdatapkt = 0;
629 ap->nsentctlpkt = 0;
630 ap->nsentdatapkt = 0;
631 ap->callback = NULL;
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700632 mutex_init(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 skb_queue_head_init(&ap->recv_queue);
David Howellsc4028952006-11-22 14:57:56 +0000634 INIT_WORK(&ap->recv_work, recv_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 ap->release_in_progress = 0;
636
637 write_unlock_irqrestore(&application_lock, flags);
638
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800639 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000641 if (!capi_controller[i] ||
642 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000644 register_appl(capi_controller[i], applid, &ap->rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800646 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 if (showcapimsgs & 1) {
649 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
650 }
651
652 return CAPI_NOERROR;
653}
654
655EXPORT_SYMBOL(capi20_register);
656
Tilman Schmidt554f2002009-04-23 02:24:21 +0000657/**
658 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
659 * @ap: CAPI application descriptor structure.
660 *
661 * Terminate an application's registration with CAPI.
662 * After this function returns successfully, the message receive
663 * callback function @ap->recv_message() will no longer be called.
664 * Return value: CAPI result code
665 */
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667u16 capi20_release(struct capi20_appl *ap)
668{
669 int i;
670 unsigned long flags;
671
672 DBG("applid %#x", ap->applid);
673
674 write_lock_irqsave(&application_lock, flags);
675 ap->release_in_progress = 1;
676 capi_applications[ap->applid - 1] = NULL;
677 write_unlock_irqrestore(&application_lock, flags);
678
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800679 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000681 if (!capi_controller[i] ||
682 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000684 release_appl(capi_controller[i], ap->applid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800686 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 flush_scheduled_work();
689 skb_queue_purge(&ap->recv_queue);
690
691 if (showcapimsgs & 1) {
692 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
693 }
694
695 return CAPI_NOERROR;
696}
697
698EXPORT_SYMBOL(capi20_release);
699
Tilman Schmidt554f2002009-04-23 02:24:21 +0000700/**
701 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
702 * @ap: CAPI application descriptor structure.
703 * @skb: CAPI message.
704 *
705 * Transfer a single message to CAPI.
706 * Return value: CAPI result code
707 */
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
710{
Jan Kiszka52253032010-02-08 10:12:10 +0000711 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 int showctl = 0;
713 u8 cmd, subcmd;
714
715 DBG("applid %#x", ap->applid);
716
Jan Kiszka52253032010-02-08 10:12:10 +0000717 if (ncontrollers == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return CAPI_REGNOTINSTALLED;
719 if ((ap->applid == 0) || ap->release_in_progress)
720 return CAPI_ILLAPPNR;
721 if (skb->len < 12
722 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
723 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
724 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
Jan Kiszka52253032010-02-08 10:12:10 +0000725 ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
726 if (!ctr || ctr->state != CAPI_CTR_RUNNING) {
727 ctr = get_capi_ctr_by_nr(1); /* XXX why? */
728 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return CAPI_REGNOTINSTALLED;
730 }
Jan Kiszka52253032010-02-08 10:12:10 +0000731 if (ctr->blocked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return CAPI_SENDQUEUEFULL;
733
734 cmd = CAPIMSG_COMMAND(skb->data);
735 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
736
737 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
Jan Kiszka52253032010-02-08 10:12:10 +0000738 ctr->nsentdatapkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 ap->nsentdatapkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000740 if (ctr->traceflag > 2)
741 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000743 ctr->nsentctlpkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 ap->nsentctlpkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000745 if (ctr->traceflag)
746 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 }
Jan Kiszka52253032010-02-08 10:12:10 +0000748 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if (showctl & 2) {
750 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800751 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 CAPIMSG_CONTROLLER(skb->data),
753 CAPIMSG_APPID(skb->data),
754 capi_cmd2str(cmd, subcmd),
755 CAPIMSG_LEN(skb->data));
756 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800757 _cdebbuf *cdb = capi_message2str(skb->data);
758 if (cdb) {
759 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
760 CAPIMSG_CONTROLLER(skb->data),
761 cdb->buf);
762 cdebbuf_free(cdb);
763 } else
764 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
765 CAPIMSG_CONTROLLER(skb->data),
766 CAPIMSG_APPID(skb->data),
767 capi_cmd2str(cmd, subcmd),
768 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 }
Jan Kiszka52253032010-02-08 10:12:10 +0000771 return ctr->send_message(ctr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772}
773
774EXPORT_SYMBOL(capi20_put_message);
775
Tilman Schmidt554f2002009-04-23 02:24:21 +0000776/**
777 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
778 * @contr: controller number.
779 * @buf: result buffer (64 bytes).
780 *
781 * Retrieve information about the manufacturer of the specified ISDN controller
782 * or (for @contr == 0) the driver itself.
783 * Return value: CAPI result code
784 */
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786u16 capi20_get_manufacturer(u32 contr, u8 *buf)
787{
Jan Kiszka52253032010-02-08 10:12:10 +0000788 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 if (contr == 0) {
791 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
792 return CAPI_NOERROR;
793 }
Jan Kiszka52253032010-02-08 10:12:10 +0000794 ctr = get_capi_ctr_by_nr(contr);
795 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return CAPI_REGNOTINSTALLED;
Jan Kiszka52253032010-02-08 10:12:10 +0000797 strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 return CAPI_NOERROR;
799}
800
801EXPORT_SYMBOL(capi20_get_manufacturer);
802
Tilman Schmidt554f2002009-04-23 02:24:21 +0000803/**
804 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
805 * @contr: controller number.
806 * @verp: result structure.
807 *
808 * Retrieve version information for the specified ISDN controller
809 * or (for @contr == 0) the driver itself.
810 * Return value: CAPI result code
811 */
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813u16 capi20_get_version(u32 contr, struct capi_version *verp)
814{
Jan Kiszka52253032010-02-08 10:12:10 +0000815 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 if (contr == 0) {
818 *verp = driver_version;
819 return CAPI_NOERROR;
820 }
Jan Kiszka52253032010-02-08 10:12:10 +0000821 ctr = get_capi_ctr_by_nr(contr);
822 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return CAPI_REGNOTINSTALLED;
824
Jan Kiszka52253032010-02-08 10:12:10 +0000825 memcpy(verp, &ctr->version, sizeof(capi_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 return CAPI_NOERROR;
827}
828
829EXPORT_SYMBOL(capi20_get_version);
830
Tilman Schmidt554f2002009-04-23 02:24:21 +0000831/**
832 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
833 * @contr: controller number.
834 * @serial: result buffer (8 bytes).
835 *
836 * Retrieve the serial number of the specified ISDN controller
837 * or (for @contr == 0) the driver itself.
838 * Return value: CAPI result code
839 */
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841u16 capi20_get_serial(u32 contr, u8 *serial)
842{
Jan Kiszka52253032010-02-08 10:12:10 +0000843 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if (contr == 0) {
846 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
847 return CAPI_NOERROR;
848 }
Jan Kiszka52253032010-02-08 10:12:10 +0000849 ctr = get_capi_ctr_by_nr(contr);
850 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return CAPI_REGNOTINSTALLED;
852
Jan Kiszka52253032010-02-08 10:12:10 +0000853 strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return CAPI_NOERROR;
855}
856
857EXPORT_SYMBOL(capi20_get_serial);
858
Tilman Schmidt554f2002009-04-23 02:24:21 +0000859/**
860 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
861 * @contr: controller number.
862 * @profp: result structure.
863 *
864 * Retrieve capability information for the specified ISDN controller
865 * or (for @contr == 0) the number of installed controllers.
866 * Return value: CAPI result code
867 */
868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
870{
Jan Kiszka52253032010-02-08 10:12:10 +0000871 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873 if (contr == 0) {
Jan Kiszka52253032010-02-08 10:12:10 +0000874 profp->ncontroller = ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return CAPI_NOERROR;
876 }
Jan Kiszka52253032010-02-08 10:12:10 +0000877 ctr = get_capi_ctr_by_nr(contr);
878 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return CAPI_REGNOTINSTALLED;
880
Jan Kiszka52253032010-02-08 10:12:10 +0000881 memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return CAPI_NOERROR;
883}
884
885EXPORT_SYMBOL(capi20_get_profile);
886
Robert P. J. Day37772ac2008-04-28 02:14:42 -0700887#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888static int old_capi_manufacturer(unsigned int cmd, void __user *data)
889{
890 avmb1_loadandconfigdef ldef;
891 avmb1_extcarddef cdef;
892 avmb1_resetdef rdef;
893 capicardparams cparams;
Jan Kiszka52253032010-02-08 10:12:10 +0000894 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 struct capi_driver *driver = NULL;
896 capiloaddata ldata;
897 struct list_head *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 int retval;
899
900 switch (cmd) {
901 case AVMB1_ADDCARD:
902 case AVMB1_ADDCARD_WITH_TYPE:
903 if (cmd == AVMB1_ADDCARD) {
904 if ((retval = copy_from_user(&cdef, data,
905 sizeof(avmb1_carddef))))
906 return retval;
907 cdef.cardtype = AVM_CARDTYPE_B1;
908 } else {
909 if ((retval = copy_from_user(&cdef, data,
910 sizeof(avmb1_extcarddef))))
911 return retval;
912 }
913 cparams.port = cdef.port;
914 cparams.irq = cdef.irq;
915 cparams.cardnr = cdef.cardnr;
916
Jan Kiszka9717fb82010-02-08 10:12:11 +0000917 mutex_lock(&capi_drivers_lock);
918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 switch (cdef.cardtype) {
920 case AVM_CARDTYPE_B1:
921 list_for_each(l, &capi_drivers) {
922 driver = list_entry(l, struct capi_driver, list);
923 if (strcmp(driver->name, "b1isa") == 0)
924 break;
925 }
926 break;
927 case AVM_CARDTYPE_T1:
928 list_for_each(l, &capi_drivers) {
929 driver = list_entry(l, struct capi_driver, list);
930 if (strcmp(driver->name, "t1isa") == 0)
931 break;
932 }
933 break;
934 default:
935 driver = NULL;
936 break;
937 }
938 if (!driver) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 printk(KERN_ERR "kcapi: driver not loaded.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000940 retval = -EIO;
941 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 printk(KERN_ERR "kcapi: driver has no add card function.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000943 retval = -EIO;
944 } else
945 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Jan Kiszka9717fb82010-02-08 10:12:11 +0000947 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 return retval;
949
950 case AVMB1_LOAD:
951 case AVMB1_LOAD_AND_CONFIG:
952
953 if (cmd == AVMB1_LOAD) {
954 if (copy_from_user(&ldef, data,
955 sizeof(avmb1_loaddef)))
956 return -EFAULT;
957 ldef.t4config.len = 0;
958 ldef.t4config.data = NULL;
959 } else {
960 if (copy_from_user(&ldef, data,
961 sizeof(avmb1_loadandconfigdef)))
962 return -EFAULT;
963 }
Jan Kiszka52253032010-02-08 10:12:10 +0000964 ctr = get_capi_ctr_by_nr(ldef.contr);
965 if (!ctr)
Jesper Juhle8a285b2007-10-16 01:27:52 -0700966 return -EINVAL;
Jan Kiszka52253032010-02-08 10:12:10 +0000967 ctr = capi_ctr_get(ctr);
968 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return -ESRCH;
Jan Kiszka52253032010-02-08 10:12:10 +0000970 if (ctr->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 printk(KERN_DEBUG "kcapi: load: no load function\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000972 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return -ESRCH;
974 }
975
976 if (ldef.t4file.len <= 0) {
977 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Jan Kiszka52253032010-02-08 10:12:10 +0000978 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return -EINVAL;
980 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -0700981 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000983 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return -EINVAL;
985 }
986
987 ldata.firmware.user = 1;
988 ldata.firmware.data = ldef.t4file.data;
989 ldata.firmware.len = ldef.t4file.len;
990 ldata.configuration.user = 1;
991 ldata.configuration.data = ldef.t4config.data;
992 ldata.configuration.len = ldef.t4config.len;
993
Jan Kiszka52253032010-02-08 10:12:10 +0000994 if (ctr->state != CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Jan Kiszka52253032010-02-08 10:12:10 +0000996 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return -EBUSY;
998 }
Jan Kiszka52253032010-02-08 10:12:10 +0000999 ctr->state = CAPI_CTR_LOADING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Jan Kiszka52253032010-02-08 10:12:10 +00001001 retval = ctr->load_firmware(ctr, &ldata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 if (retval) {
Jan Kiszka52253032010-02-08 10:12:10 +00001004 ctr->state = CAPI_CTR_DETECTED;
1005 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 return retval;
1007 }
1008
Jan Kiszka52253032010-02-08 10:12:10 +00001009 while (ctr->state != CAPI_CTR_RUNNING) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 msleep_interruptible(100); /* 0.1 sec */
1012
1013 if (signal_pending(current)) {
Jan Kiszka52253032010-02-08 10:12:10 +00001014 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return -EINTR;
1016 }
1017 }
Jan Kiszka52253032010-02-08 10:12:10 +00001018 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return 0;
1020
1021 case AVMB1_RESETCARD:
1022 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1023 return -EFAULT;
Jan Kiszka52253032010-02-08 10:12:10 +00001024 ctr = get_capi_ctr_by_nr(rdef.contr);
1025 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return -ESRCH;
1027
Jan Kiszka52253032010-02-08 10:12:10 +00001028 if (ctr->state == CAPI_CTR_DETECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return 0;
1030
Jan Kiszka52253032010-02-08 10:12:10 +00001031 ctr->reset_ctr(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Jan Kiszka52253032010-02-08 10:12:10 +00001033 while (ctr->state > CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035 msleep_interruptible(100); /* 0.1 sec */
1036
1037 if (signal_pending(current))
1038 return -EINTR;
1039 }
1040 return 0;
1041
1042 }
1043 return -EINVAL;
1044}
1045#endif
1046
Tilman Schmidt554f2002009-04-23 02:24:21 +00001047/**
1048 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1049 * @cmd: command.
1050 * @data: parameter.
1051 *
1052 * Perform manufacturer specific command.
1053 * Return value: CAPI result code
1054 */
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056int capi20_manufacturer(unsigned int cmd, void __user *data)
1057{
Jan Kiszka52253032010-02-08 10:12:10 +00001058 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001061#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 case AVMB1_LOAD:
1063 case AVMB1_LOAD_AND_CONFIG:
1064 case AVMB1_RESETCARD:
1065 case AVMB1_GET_CARDINFO:
1066 case AVMB1_REMOVECARD:
1067 return old_capi_manufacturer(cmd, data);
1068#endif
1069 case KCAPI_CMD_TRACE:
1070 {
1071 kcapi_flagdef fdef;
1072
1073 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1074 return -EFAULT;
1075
Jan Kiszka52253032010-02-08 10:12:10 +00001076 ctr = get_capi_ctr_by_nr(fdef.contr);
1077 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return -ESRCH;
1079
Jan Kiszka52253032010-02-08 10:12:10 +00001080 ctr->traceflag = fdef.flag;
Karsten Keil17f0cd22007-02-28 20:13:50 -08001081 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
Jan Kiszka52253032010-02-08 10:12:10 +00001082 ctr->cnr, ctr->traceflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return 0;
1084 }
1085 case KCAPI_CMD_ADDCARD:
1086 {
1087 struct list_head *l;
1088 struct capi_driver *driver = NULL;
1089 capicardparams cparams;
1090 kcapi_carddef cdef;
1091 int retval;
1092
1093 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1094 return retval;
1095
1096 cparams.port = cdef.port;
1097 cparams.irq = cdef.irq;
1098 cparams.membase = cdef.membase;
1099 cparams.cardnr = cdef.cardnr;
1100 cparams.cardtype = 0;
1101 cdef.driver[sizeof(cdef.driver)-1] = 0;
1102
Jan Kiszka9717fb82010-02-08 10:12:11 +00001103 mutex_lock(&capi_drivers_lock);
1104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 list_for_each(l, &capi_drivers) {
1106 driver = list_entry(l, struct capi_driver, list);
1107 if (strcmp(driver->name, cdef.driver) == 0)
1108 break;
1109 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001110 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1112 cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001113 retval = -ESRCH;
1114 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001116 retval = -EIO;
1117 } else
1118 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Jan Kiszka9717fb82010-02-08 10:12:11 +00001120 mutex_unlock(&capi_drivers_lock);
1121 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
1123
1124 default:
1125 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1126 cmd);
1127 break;
1128
1129 }
1130 return -EINVAL;
1131}
1132
1133EXPORT_SYMBOL(capi20_manufacturer);
1134
1135/* temporary hack */
Tilman Schmidt554f2002009-04-23 02:24:21 +00001136
1137/**
1138 * capi20_set_callback() - set CAPI application notification callback function
1139 * @ap: CAPI application descriptor structure.
1140 * @callback: callback function (NULL to remove).
1141 *
1142 * If not NULL, the callback function will be called to notify the
1143 * application of the addition or removal of a controller.
1144 * The first argument (cmd) will tell whether the controller was added
1145 * (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
1146 * The second argument (contr) will be the controller number.
1147 * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
1148 * new controller's capability profile structure.
1149 */
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151void capi20_set_callback(struct capi20_appl *ap,
1152 void (*callback) (unsigned int cmd, __u32 contr, void *data))
1153{
1154 ap->callback = callback;
1155}
1156
1157EXPORT_SYMBOL(capi20_set_callback);
1158
1159/* ------------------------------------------------------------- */
1160/* -------- Init & Cleanup ------------------------------------- */
1161/* ------------------------------------------------------------- */
1162
1163/*
1164 * init / exit functions
1165 */
1166
1167static int __init kcapi_init(void)
1168{
Jan Kiszka88549d62010-02-08 10:12:09 +00001169 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Jan Kiszka88549d62010-02-08 10:12:09 +00001171 err = cdebug_init();
1172 if (!err)
1173 kcapi_proc_init();
1174 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175}
1176
1177static void __exit kcapi_exit(void)
1178{
1179 kcapi_proc_exit();
1180
1181 /* make sure all notifiers are finished */
1182 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001183 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184}
1185
1186module_init(kcapi_init);
1187module_exit(kcapi_exit);