blob: 9362a7a66aa15f5f8fa2321fa30801c930118687 [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{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 struct capi20_appl *ap;
Jan Kiszka3efecf72010-02-08 10:12:12 +0000173 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 u16 applid;
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)
182 return;
183
184 ctr->state = CAPI_CTR_RUNNING;
185
186 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
187 ap = get_capi_appl_by_nr(applid);
188 if (!ap || ap->release_in_progress)
189 continue;
190 register_appl(ctr, applid, &ap->rparam);
191 if (ap->callback && !ap->release_in_progress)
192 ap->callback(KCI_CONTRUP, contr,
193 &ctr->profile);
194 }
195 } else
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700196 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
199/* -------- KCI_CONTRDOWN ------------------------------------- */
200
Jan Kiszka3efecf72010-02-08 10:12:12 +0000201static void ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 struct capi20_appl *ap;
204 u16 applid;
205
Jan Kiszka3efecf72010-02-08 10:12:12 +0000206 if (ctr->state == CAPI_CTR_DETECTED)
207 return;
208
209 ctr->state = CAPI_CTR_DETECTED;
210
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 Kiszka3efecf72010-02-08 10:12:12 +0000218 if (ap && !ap->release_in_progress) {
219 if (ap->callback)
220 ap->callback(KCI_CONTRDOWN, ctr->cnr, NULL);
221 capi_ctr_put(ctr);
222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 }
224}
225
Jan Kiszka3efecf72010-02-08 10:12:12 +0000226static void notify_down(u32 contr)
227{
228 struct capi_ctr *ctr;
229
230 if (showcapimsgs & 1)
231 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
232
233 ctr = get_capi_ctr_by_nr(contr);
234 if (ctr)
235 ctr_down(ctr);
236 else
237 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
238}
239
David Howellsc4028952006-11-22 14:57:56 +0000240static void notify_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
David Howellsc4028952006-11-22 14:57:56 +0000242 struct capi_notifier *np =
243 container_of(work, struct capi_notifier, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 switch (np->cmd) {
246 case KCI_CONTRUP:
247 notify_up(np->controller);
248 break;
249 case KCI_CONTRDOWN:
250 notify_down(np->controller);
251 break;
252 }
253
254 kfree(np);
255}
256
257/*
258 * The notifier will result in adding/deleteing of devices. Devices can
259 * only removed in user process, not in bh.
260 */
261static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
262{
263 struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
264
265 if (!np)
266 return -ENOMEM;
267
David Howellsc4028952006-11-22 14:57:56 +0000268 INIT_WORK(&np->work, notify_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 np->cmd = cmd;
270 np->controller = controller;
271 np->applid = applid;
272 np->ncci = ncci;
273
274 schedule_work(&np->work);
275 return 0;
276}
277
278
279/* -------- Receiver ------------------------------------------ */
280
David Howellsc4028952006-11-22 14:57:56 +0000281static void recv_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
283 struct sk_buff *skb;
David Howellsc4028952006-11-22 14:57:56 +0000284 struct capi20_appl *ap =
285 container_of(work, struct capi20_appl, recv_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if ((!ap) || (ap->release_in_progress))
288 return;
289
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700290 mutex_lock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 while ((skb = skb_dequeue(&ap->recv_queue))) {
292 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
293 ap->nrecvdatapkt++;
294 else
295 ap->nrecvctlpkt++;
296
297 ap->recv_message(ap, skb);
298 }
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700299 mutex_unlock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Tilman Schmidt554f2002009-04-23 02:24:21 +0000302/**
303 * capi_ctr_handle_message() - handle incoming CAPI message
Jan Kiszka52253032010-02-08 10:12:10 +0000304 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000305 * @appl: application ID.
306 * @skb: message.
307 *
308 * Called by hardware driver to pass a CAPI message to the application.
309 */
310
Jan Kiszka52253032010-02-08 10:12:10 +0000311void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
312 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 struct capi20_appl *ap;
315 int showctl = 0;
316 u8 cmd, subcmd;
317 unsigned long flags;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800318 _cdebbuf *cdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Jan Kiszka52253032010-02-08 10:12:10 +0000320 if (ctr->state != CAPI_CTR_RUNNING) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800321 cdb = capi_message2str(skb->data);
322 if (cdb) {
323 printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
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_INFO "kcapi: controller [%03d] not active, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000328 ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 goto error;
330 }
331
332 cmd = CAPIMSG_COMMAND(skb->data);
333 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
334 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
Jan Kiszka52253032010-02-08 10:12:10 +0000335 ctr->nrecvdatapkt++;
336 if (ctr->traceflag > 2)
337 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000339 ctr->nrecvctlpkt++;
340 if (ctr->traceflag)
341 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 }
Jan Kiszka52253032010-02-08 10:12:10 +0000343 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 if (showctl & 2) {
345 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800346 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000347 ctr->cnr, CAPIMSG_APPID(skb->data),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 capi_cmd2str(cmd, subcmd),
349 CAPIMSG_LEN(skb->data));
350 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800351 cdb = capi_message2str(skb->data);
352 if (cdb) {
353 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000354 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800355 cdebbuf_free(cdb);
356 } else
357 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000358 ctr->cnr, CAPIMSG_APPID(skb->data),
Karsten Keil17f0cd22007-02-28 20:13:50 -0800359 capi_cmd2str(cmd, subcmd),
360 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
362
363 }
364
365 read_lock_irqsave(&application_lock, flags);
366 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
367 if ((!ap) || (ap->release_in_progress)) {
368 read_unlock_irqrestore(&application_lock, flags);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800369 cdb = capi_message2str(skb->data);
370 if (cdb) {
371 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
372 CAPIMSG_APPID(skb->data), cdb->buf);
373 cdebbuf_free(cdb);
374 } else
375 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
376 CAPIMSG_APPID(skb->data),
377 capi_cmd2str(cmd, subcmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto error;
379 }
380 skb_queue_tail(&ap->recv_queue, skb);
381 schedule_work(&ap->recv_work);
382 read_unlock_irqrestore(&application_lock, flags);
383
384 return;
385
386error:
387 kfree_skb(skb);
388}
389
390EXPORT_SYMBOL(capi_ctr_handle_message);
391
Tilman Schmidt554f2002009-04-23 02:24:21 +0000392/**
393 * capi_ctr_ready() - signal CAPI controller ready
Jan Kiszka52253032010-02-08 10:12:10 +0000394 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000395 *
396 * Called by hardware driver to signal that the controller is up and running.
397 */
398
Jan Kiszka52253032010-02-08 10:12:10 +0000399void capi_ctr_ready(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Jan Kiszka52253032010-02-08 10:12:10 +0000401 printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
402 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Jan Kiszka52253032010-02-08 10:12:10 +0000404 notify_push(KCI_CONTRUP, ctr->cnr, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
407EXPORT_SYMBOL(capi_ctr_ready);
408
Tilman Schmidt554f2002009-04-23 02:24:21 +0000409/**
Tilman Schmidt4e329972009-06-07 09:09:23 +0000410 * capi_ctr_down() - signal CAPI controller not ready
Jan Kiszka52253032010-02-08 10:12:10 +0000411 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000412 *
413 * Called by hardware driver to signal that the controller is down and
414 * unavailable for use.
415 */
416
Jan Kiszka52253032010-02-08 10:12:10 +0000417void capi_ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Jan Kiszka52253032010-02-08 10:12:10 +0000419 printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Jan Kiszka52253032010-02-08 10:12:10 +0000421 notify_push(KCI_CONTRDOWN, ctr->cnr, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
423
Tilman Schmidt4e329972009-06-07 09:09:23 +0000424EXPORT_SYMBOL(capi_ctr_down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Tilman Schmidt554f2002009-04-23 02:24:21 +0000426/**
427 * capi_ctr_suspend_output() - suspend controller
Jan Kiszka52253032010-02-08 10:12:10 +0000428 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000429 *
430 * Called by hardware driver to stop data flow.
431 */
432
Jan Kiszka52253032010-02-08 10:12:10 +0000433void capi_ctr_suspend_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Jan Kiszka52253032010-02-08 10:12:10 +0000435 if (!ctr->blocked) {
436 printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
437 ctr->cnr);
438 ctr->blocked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440}
441
442EXPORT_SYMBOL(capi_ctr_suspend_output);
443
Tilman Schmidt554f2002009-04-23 02:24:21 +0000444/**
445 * capi_ctr_resume_output() - resume controller
Jan Kiszka52253032010-02-08 10:12:10 +0000446 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000447 *
448 * Called by hardware driver to resume data flow.
449 */
450
Jan Kiszka52253032010-02-08 10:12:10 +0000451void capi_ctr_resume_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Jan Kiszka52253032010-02-08 10:12:10 +0000453 if (ctr->blocked) {
454 printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
455 ctr->cnr);
456 ctr->blocked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
458}
459
460EXPORT_SYMBOL(capi_ctr_resume_output);
461
462/* ------------------------------------------------------------- */
463
Tilman Schmidt554f2002009-04-23 02:24:21 +0000464/**
465 * attach_capi_ctr() - register CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000466 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000467 *
468 * Called by hardware driver to register a controller with the CAPI subsystem.
469 * Return value: 0 on success, error code < 0 on error
470 */
471
Jan Kiszka52253032010-02-08 10:12:10 +0000472int attach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
474 int i;
475
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800476 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000479 if (!capi_controller[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 break;
481 }
482 if (i == CAPI_MAXCONTR) {
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800483 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 printk(KERN_ERR "kcapi: out of controller slots\n");
485 return -EBUSY;
486 }
Jan Kiszka52253032010-02-08 10:12:10 +0000487 capi_controller[i] = ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800489 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Jan Kiszka52253032010-02-08 10:12:10 +0000491 ctr->nrecvctlpkt = 0;
492 ctr->nrecvdatapkt = 0;
493 ctr->nsentctlpkt = 0;
494 ctr->nsentdatapkt = 0;
495 ctr->cnr = i + 1;
496 ctr->state = CAPI_CTR_DETECTED;
497 ctr->blocked = 0;
498 ctr->traceflag = showcapimsgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Jan Kiszka52253032010-02-08 10:12:10 +0000500 sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
501 ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Jan Kiszka52253032010-02-08 10:12:10 +0000503 ncontrollers++;
504 printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
505 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return 0;
507}
508
509EXPORT_SYMBOL(attach_capi_ctr);
510
Tilman Schmidt554f2002009-04-23 02:24:21 +0000511/**
512 * detach_capi_ctr() - unregister CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000513 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000514 *
515 * Called by hardware driver to remove the registration of a controller
516 * with the CAPI subsystem.
517 * Return value: 0 on success, error code < 0 on error
518 */
519
Jan Kiszka52253032010-02-08 10:12:10 +0000520int detach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Jan Kiszka3efecf72010-02-08 10:12:12 +0000522 ctr_down(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Jan Kiszka52253032010-02-08 10:12:10 +0000524 ncontrollers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Jan Kiszka52253032010-02-08 10:12:10 +0000526 if (ctr->procent) {
527 remove_proc_entry(ctr->procfn, NULL);
528 ctr->procent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Jan Kiszka52253032010-02-08 10:12:10 +0000530 capi_controller[ctr->cnr - 1] = NULL;
531 printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
532 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 return 0;
535}
536
537EXPORT_SYMBOL(detach_capi_ctr);
538
Tilman Schmidt554f2002009-04-23 02:24:21 +0000539/**
540 * register_capi_driver() - register CAPI driver
541 * @driver: driver descriptor structure.
542 *
543 * Called by hardware driver to register itself with the CAPI subsystem.
544 */
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546void register_capi_driver(struct capi_driver *driver)
547{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000548 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 list_add_tail(&driver->list, &capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000550 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
553EXPORT_SYMBOL(register_capi_driver);
554
Tilman Schmidt554f2002009-04-23 02:24:21 +0000555/**
556 * unregister_capi_driver() - unregister CAPI driver
557 * @driver: driver descriptor structure.
558 *
559 * Called by hardware driver to unregister itself from the CAPI subsystem.
560 */
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562void unregister_capi_driver(struct capi_driver *driver)
563{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000564 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 list_del(&driver->list);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000566 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
569EXPORT_SYMBOL(unregister_capi_driver);
570
571/* ------------------------------------------------------------- */
572/* -------- CAPI2.0 Interface ---------------------------------- */
573/* ------------------------------------------------------------- */
574
Tilman Schmidt554f2002009-04-23 02:24:21 +0000575/**
576 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
577 *
578 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
579 * is ready for use, CAPI_REGNOTINSTALLED otherwise)
580 */
581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582u16 capi20_isinstalled(void)
583{
584 int i;
585 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000586 if (capi_controller[i] &&
587 capi_controller[i]->state == CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return CAPI_NOERROR;
589 }
590 return CAPI_REGNOTINSTALLED;
591}
592
593EXPORT_SYMBOL(capi20_isinstalled);
594
Tilman Schmidt554f2002009-04-23 02:24:21 +0000595/**
596 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
597 * @ap: CAPI application descriptor structure.
598 *
599 * Register an application's presence with CAPI.
600 * A unique application ID is assigned and stored in @ap->applid.
601 * After this function returns successfully, the message receive
602 * callback function @ap->recv_message() may be called at any time
603 * until capi20_release() has been called for the same @ap.
604 * Return value: CAPI result code
605 */
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607u16 capi20_register(struct capi20_appl *ap)
608{
609 int i;
610 u16 applid;
611 unsigned long flags;
612
613 DBG("");
614
615 if (ap->rparam.datablklen < 128)
616 return CAPI_LOGBLKSIZETOSMALL;
617
618 write_lock_irqsave(&application_lock, flags);
619
620 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
621 if (capi_applications[applid - 1] == NULL)
622 break;
623 }
624 if (applid > CAPI_MAXAPPL) {
625 write_unlock_irqrestore(&application_lock, flags);
626 return CAPI_TOOMANYAPPLS;
627 }
628
629 ap->applid = applid;
630 capi_applications[applid - 1] = ap;
631
632 ap->nrecvctlpkt = 0;
633 ap->nrecvdatapkt = 0;
634 ap->nsentctlpkt = 0;
635 ap->nsentdatapkt = 0;
636 ap->callback = NULL;
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700637 mutex_init(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 skb_queue_head_init(&ap->recv_queue);
David Howellsc4028952006-11-22 14:57:56 +0000639 INIT_WORK(&ap->recv_work, recv_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 ap->release_in_progress = 0;
641
642 write_unlock_irqrestore(&application_lock, flags);
643
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800644 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000646 if (!capi_controller[i] ||
647 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000649 register_appl(capi_controller[i], applid, &ap->rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800651 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 if (showcapimsgs & 1) {
654 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
655 }
656
657 return CAPI_NOERROR;
658}
659
660EXPORT_SYMBOL(capi20_register);
661
Tilman Schmidt554f2002009-04-23 02:24:21 +0000662/**
663 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
664 * @ap: CAPI application descriptor structure.
665 *
666 * Terminate an application's registration with CAPI.
667 * After this function returns successfully, the message receive
668 * callback function @ap->recv_message() will no longer be called.
669 * Return value: CAPI result code
670 */
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672u16 capi20_release(struct capi20_appl *ap)
673{
674 int i;
675 unsigned long flags;
676
677 DBG("applid %#x", ap->applid);
678
679 write_lock_irqsave(&application_lock, flags);
680 ap->release_in_progress = 1;
681 capi_applications[ap->applid - 1] = NULL;
682 write_unlock_irqrestore(&application_lock, flags);
683
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800684 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000686 if (!capi_controller[i] ||
687 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000689 release_appl(capi_controller[i], ap->applid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800691 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 flush_scheduled_work();
694 skb_queue_purge(&ap->recv_queue);
695
696 if (showcapimsgs & 1) {
697 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
698 }
699
700 return CAPI_NOERROR;
701}
702
703EXPORT_SYMBOL(capi20_release);
704
Tilman Schmidt554f2002009-04-23 02:24:21 +0000705/**
706 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
707 * @ap: CAPI application descriptor structure.
708 * @skb: CAPI message.
709 *
710 * Transfer a single message to CAPI.
711 * Return value: CAPI result code
712 */
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
715{
Jan Kiszka52253032010-02-08 10:12:10 +0000716 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 int showctl = 0;
718 u8 cmd, subcmd;
719
720 DBG("applid %#x", ap->applid);
721
Jan Kiszka52253032010-02-08 10:12:10 +0000722 if (ncontrollers == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return CAPI_REGNOTINSTALLED;
724 if ((ap->applid == 0) || ap->release_in_progress)
725 return CAPI_ILLAPPNR;
726 if (skb->len < 12
727 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
728 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
729 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
Jan Kiszka52253032010-02-08 10:12:10 +0000730 ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
731 if (!ctr || ctr->state != CAPI_CTR_RUNNING) {
732 ctr = get_capi_ctr_by_nr(1); /* XXX why? */
733 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return CAPI_REGNOTINSTALLED;
735 }
Jan Kiszka52253032010-02-08 10:12:10 +0000736 if (ctr->blocked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return CAPI_SENDQUEUEFULL;
738
739 cmd = CAPIMSG_COMMAND(skb->data);
740 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
741
742 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
Jan Kiszka52253032010-02-08 10:12:10 +0000743 ctr->nsentdatapkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 ap->nsentdatapkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000745 if (ctr->traceflag > 2)
746 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000748 ctr->nsentctlpkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 ap->nsentctlpkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000750 if (ctr->traceflag)
751 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
Jan Kiszka52253032010-02-08 10:12:10 +0000753 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (showctl & 2) {
755 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800756 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 CAPIMSG_CONTROLLER(skb->data),
758 CAPIMSG_APPID(skb->data),
759 capi_cmd2str(cmd, subcmd),
760 CAPIMSG_LEN(skb->data));
761 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800762 _cdebbuf *cdb = capi_message2str(skb->data);
763 if (cdb) {
764 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
765 CAPIMSG_CONTROLLER(skb->data),
766 cdb->buf);
767 cdebbuf_free(cdb);
768 } else
769 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
770 CAPIMSG_CONTROLLER(skb->data),
771 CAPIMSG_APPID(skb->data),
772 capi_cmd2str(cmd, subcmd),
773 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Jan Kiszka52253032010-02-08 10:12:10 +0000776 return ctr->send_message(ctr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777}
778
779EXPORT_SYMBOL(capi20_put_message);
780
Tilman Schmidt554f2002009-04-23 02:24:21 +0000781/**
782 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
783 * @contr: controller number.
784 * @buf: result buffer (64 bytes).
785 *
786 * Retrieve information about the manufacturer of the specified ISDN controller
787 * or (for @contr == 0) the driver itself.
788 * Return value: CAPI result code
789 */
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791u16 capi20_get_manufacturer(u32 contr, u8 *buf)
792{
Jan Kiszka52253032010-02-08 10:12:10 +0000793 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (contr == 0) {
796 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
797 return CAPI_NOERROR;
798 }
Jan Kiszka52253032010-02-08 10:12:10 +0000799 ctr = get_capi_ctr_by_nr(contr);
800 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 return CAPI_REGNOTINSTALLED;
Jan Kiszka52253032010-02-08 10:12:10 +0000802 strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return CAPI_NOERROR;
804}
805
806EXPORT_SYMBOL(capi20_get_manufacturer);
807
Tilman Schmidt554f2002009-04-23 02:24:21 +0000808/**
809 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
810 * @contr: controller number.
811 * @verp: result structure.
812 *
813 * Retrieve version information for the specified ISDN controller
814 * or (for @contr == 0) the driver itself.
815 * Return value: CAPI result code
816 */
817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818u16 capi20_get_version(u32 contr, struct capi_version *verp)
819{
Jan Kiszka52253032010-02-08 10:12:10 +0000820 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 if (contr == 0) {
823 *verp = driver_version;
824 return CAPI_NOERROR;
825 }
Jan Kiszka52253032010-02-08 10:12:10 +0000826 ctr = get_capi_ctr_by_nr(contr);
827 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return CAPI_REGNOTINSTALLED;
829
Jan Kiszka52253032010-02-08 10:12:10 +0000830 memcpy(verp, &ctr->version, sizeof(capi_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return CAPI_NOERROR;
832}
833
834EXPORT_SYMBOL(capi20_get_version);
835
Tilman Schmidt554f2002009-04-23 02:24:21 +0000836/**
837 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
838 * @contr: controller number.
839 * @serial: result buffer (8 bytes).
840 *
841 * Retrieve the serial number of the specified ISDN controller
842 * or (for @contr == 0) the driver itself.
843 * Return value: CAPI result code
844 */
845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846u16 capi20_get_serial(u32 contr, u8 *serial)
847{
Jan Kiszka52253032010-02-08 10:12:10 +0000848 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 if (contr == 0) {
851 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
852 return CAPI_NOERROR;
853 }
Jan Kiszka52253032010-02-08 10:12:10 +0000854 ctr = get_capi_ctr_by_nr(contr);
855 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return CAPI_REGNOTINSTALLED;
857
Jan Kiszka52253032010-02-08 10:12:10 +0000858 strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 return CAPI_NOERROR;
860}
861
862EXPORT_SYMBOL(capi20_get_serial);
863
Tilman Schmidt554f2002009-04-23 02:24:21 +0000864/**
865 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
866 * @contr: controller number.
867 * @profp: result structure.
868 *
869 * Retrieve capability information for the specified ISDN controller
870 * or (for @contr == 0) the number of installed controllers.
871 * Return value: CAPI result code
872 */
873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
875{
Jan Kiszka52253032010-02-08 10:12:10 +0000876 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878 if (contr == 0) {
Jan Kiszka52253032010-02-08 10:12:10 +0000879 profp->ncontroller = ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return CAPI_NOERROR;
881 }
Jan Kiszka52253032010-02-08 10:12:10 +0000882 ctr = get_capi_ctr_by_nr(contr);
883 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return CAPI_REGNOTINSTALLED;
885
Jan Kiszka52253032010-02-08 10:12:10 +0000886 memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return CAPI_NOERROR;
888}
889
890EXPORT_SYMBOL(capi20_get_profile);
891
Robert P. J. Day37772ac2008-04-28 02:14:42 -0700892#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893static int old_capi_manufacturer(unsigned int cmd, void __user *data)
894{
895 avmb1_loadandconfigdef ldef;
896 avmb1_extcarddef cdef;
897 avmb1_resetdef rdef;
898 capicardparams cparams;
Jan Kiszka52253032010-02-08 10:12:10 +0000899 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 struct capi_driver *driver = NULL;
901 capiloaddata ldata;
902 struct list_head *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 int retval;
904
905 switch (cmd) {
906 case AVMB1_ADDCARD:
907 case AVMB1_ADDCARD_WITH_TYPE:
908 if (cmd == AVMB1_ADDCARD) {
909 if ((retval = copy_from_user(&cdef, data,
910 sizeof(avmb1_carddef))))
911 return retval;
912 cdef.cardtype = AVM_CARDTYPE_B1;
913 } else {
914 if ((retval = copy_from_user(&cdef, data,
915 sizeof(avmb1_extcarddef))))
916 return retval;
917 }
918 cparams.port = cdef.port;
919 cparams.irq = cdef.irq;
920 cparams.cardnr = cdef.cardnr;
921
Jan Kiszka9717fb82010-02-08 10:12:11 +0000922 mutex_lock(&capi_drivers_lock);
923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 switch (cdef.cardtype) {
925 case AVM_CARDTYPE_B1:
926 list_for_each(l, &capi_drivers) {
927 driver = list_entry(l, struct capi_driver, list);
928 if (strcmp(driver->name, "b1isa") == 0)
929 break;
930 }
931 break;
932 case AVM_CARDTYPE_T1:
933 list_for_each(l, &capi_drivers) {
934 driver = list_entry(l, struct capi_driver, list);
935 if (strcmp(driver->name, "t1isa") == 0)
936 break;
937 }
938 break;
939 default:
940 driver = NULL;
941 break;
942 }
943 if (!driver) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 printk(KERN_ERR "kcapi: driver not loaded.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000945 retval = -EIO;
946 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 printk(KERN_ERR "kcapi: driver has no add card function.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000948 retval = -EIO;
949 } else
950 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Jan Kiszka9717fb82010-02-08 10:12:11 +0000952 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return retval;
954
955 case AVMB1_LOAD:
956 case AVMB1_LOAD_AND_CONFIG:
957
958 if (cmd == AVMB1_LOAD) {
959 if (copy_from_user(&ldef, data,
960 sizeof(avmb1_loaddef)))
961 return -EFAULT;
962 ldef.t4config.len = 0;
963 ldef.t4config.data = NULL;
964 } else {
965 if (copy_from_user(&ldef, data,
966 sizeof(avmb1_loadandconfigdef)))
967 return -EFAULT;
968 }
Jan Kiszka52253032010-02-08 10:12:10 +0000969 ctr = get_capi_ctr_by_nr(ldef.contr);
970 if (!ctr)
Jesper Juhle8a285b2007-10-16 01:27:52 -0700971 return -EINVAL;
Jan Kiszka52253032010-02-08 10:12:10 +0000972 ctr = capi_ctr_get(ctr);
973 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return -ESRCH;
Jan Kiszka52253032010-02-08 10:12:10 +0000975 if (ctr->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 printk(KERN_DEBUG "kcapi: load: no load function\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000977 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return -ESRCH;
979 }
980
981 if (ldef.t4file.len <= 0) {
982 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Jan Kiszka52253032010-02-08 10:12:10 +0000983 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return -EINVAL;
985 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -0700986 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000988 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return -EINVAL;
990 }
991
992 ldata.firmware.user = 1;
993 ldata.firmware.data = ldef.t4file.data;
994 ldata.firmware.len = ldef.t4file.len;
995 ldata.configuration.user = 1;
996 ldata.configuration.data = ldef.t4config.data;
997 ldata.configuration.len = ldef.t4config.len;
998
Jan Kiszka52253032010-02-08 10:12:10 +0000999 if (ctr->state != CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Jan Kiszka52253032010-02-08 10:12:10 +00001001 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return -EBUSY;
1003 }
Jan Kiszka52253032010-02-08 10:12:10 +00001004 ctr->state = CAPI_CTR_LOADING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Jan Kiszka52253032010-02-08 10:12:10 +00001006 retval = ctr->load_firmware(ctr, &ldata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 if (retval) {
Jan Kiszka52253032010-02-08 10:12:10 +00001009 ctr->state = CAPI_CTR_DETECTED;
1010 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return retval;
1012 }
1013
Jan Kiszka52253032010-02-08 10:12:10 +00001014 while (ctr->state != CAPI_CTR_RUNNING) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 msleep_interruptible(100); /* 0.1 sec */
1017
1018 if (signal_pending(current)) {
Jan Kiszka52253032010-02-08 10:12:10 +00001019 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return -EINTR;
1021 }
1022 }
Jan Kiszka52253032010-02-08 10:12:10 +00001023 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 0;
1025
1026 case AVMB1_RESETCARD:
1027 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1028 return -EFAULT;
Jan Kiszka52253032010-02-08 10:12:10 +00001029 ctr = get_capi_ctr_by_nr(rdef.contr);
1030 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return -ESRCH;
1032
Jan Kiszka52253032010-02-08 10:12:10 +00001033 if (ctr->state == CAPI_CTR_DETECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return 0;
1035
Jan Kiszka52253032010-02-08 10:12:10 +00001036 ctr->reset_ctr(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Jan Kiszka52253032010-02-08 10:12:10 +00001038 while (ctr->state > CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
1040 msleep_interruptible(100); /* 0.1 sec */
1041
1042 if (signal_pending(current))
1043 return -EINTR;
1044 }
1045 return 0;
1046
1047 }
1048 return -EINVAL;
1049}
1050#endif
1051
Tilman Schmidt554f2002009-04-23 02:24:21 +00001052/**
1053 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1054 * @cmd: command.
1055 * @data: parameter.
1056 *
1057 * Perform manufacturer specific command.
1058 * Return value: CAPI result code
1059 */
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061int capi20_manufacturer(unsigned int cmd, void __user *data)
1062{
Jan Kiszka52253032010-02-08 10:12:10 +00001063 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001066#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 case AVMB1_LOAD:
1068 case AVMB1_LOAD_AND_CONFIG:
1069 case AVMB1_RESETCARD:
1070 case AVMB1_GET_CARDINFO:
1071 case AVMB1_REMOVECARD:
1072 return old_capi_manufacturer(cmd, data);
1073#endif
1074 case KCAPI_CMD_TRACE:
1075 {
1076 kcapi_flagdef fdef;
1077
1078 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1079 return -EFAULT;
1080
Jan Kiszka52253032010-02-08 10:12:10 +00001081 ctr = get_capi_ctr_by_nr(fdef.contr);
1082 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return -ESRCH;
1084
Jan Kiszka52253032010-02-08 10:12:10 +00001085 ctr->traceflag = fdef.flag;
Karsten Keil17f0cd22007-02-28 20:13:50 -08001086 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
Jan Kiszka52253032010-02-08 10:12:10 +00001087 ctr->cnr, ctr->traceflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return 0;
1089 }
1090 case KCAPI_CMD_ADDCARD:
1091 {
1092 struct list_head *l;
1093 struct capi_driver *driver = NULL;
1094 capicardparams cparams;
1095 kcapi_carddef cdef;
1096 int retval;
1097
1098 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1099 return retval;
1100
1101 cparams.port = cdef.port;
1102 cparams.irq = cdef.irq;
1103 cparams.membase = cdef.membase;
1104 cparams.cardnr = cdef.cardnr;
1105 cparams.cardtype = 0;
1106 cdef.driver[sizeof(cdef.driver)-1] = 0;
1107
Jan Kiszka9717fb82010-02-08 10:12:11 +00001108 mutex_lock(&capi_drivers_lock);
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 list_for_each(l, &capi_drivers) {
1111 driver = list_entry(l, struct capi_driver, list);
1112 if (strcmp(driver->name, cdef.driver) == 0)
1113 break;
1114 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001115 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1117 cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001118 retval = -ESRCH;
1119 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001121 retval = -EIO;
1122 } else
1123 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Jan Kiszka9717fb82010-02-08 10:12:11 +00001125 mutex_unlock(&capi_drivers_lock);
1126 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
1129 default:
1130 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1131 cmd);
1132 break;
1133
1134 }
1135 return -EINVAL;
1136}
1137
1138EXPORT_SYMBOL(capi20_manufacturer);
1139
1140/* temporary hack */
Tilman Schmidt554f2002009-04-23 02:24:21 +00001141
1142/**
1143 * capi20_set_callback() - set CAPI application notification callback function
1144 * @ap: CAPI application descriptor structure.
1145 * @callback: callback function (NULL to remove).
1146 *
1147 * If not NULL, the callback function will be called to notify the
1148 * application of the addition or removal of a controller.
1149 * The first argument (cmd) will tell whether the controller was added
1150 * (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
1151 * The second argument (contr) will be the controller number.
1152 * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
1153 * new controller's capability profile structure.
1154 */
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156void capi20_set_callback(struct capi20_appl *ap,
1157 void (*callback) (unsigned int cmd, __u32 contr, void *data))
1158{
1159 ap->callback = callback;
1160}
1161
1162EXPORT_SYMBOL(capi20_set_callback);
1163
1164/* ------------------------------------------------------------- */
1165/* -------- Init & Cleanup ------------------------------------- */
1166/* ------------------------------------------------------------- */
1167
1168/*
1169 * init / exit functions
1170 */
1171
1172static int __init kcapi_init(void)
1173{
Jan Kiszka88549d62010-02-08 10:12:09 +00001174 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Jan Kiszka88549d62010-02-08 10:12:09 +00001176 err = cdebug_init();
1177 if (!err)
1178 kcapi_proc_init();
1179 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180}
1181
1182static void __exit kcapi_exit(void)
1183{
1184 kcapi_proc_exit();
1185
1186 /* make sure all notifiers are finished */
1187 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001188 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189}
1190
1191module_init(kcapi_init);
1192module_exit(kcapi_exit);