blob: e08914d33be172e3dd6d69341d740c2d62043375 [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
Jan Kiszkaef69bb22010-02-08 10:12:13 +000047struct capictr_event {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 struct work_struct work;
Jan Kiszkaef69bb22010-02-08 10:12:13 +000049 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 u32 controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051};
52
53/* ------------------------------------------------------------- */
54
55static struct capi_version driver_version = {2, 0, 1, 1<<4};
56static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
57static char capi_manufakturer[64] = "AVM Berlin";
58
59#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
60
61LIST_HEAD(capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +000062DEFINE_MUTEX(capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64static DEFINE_RWLOCK(application_lock);
Arjan van de Ven9cdf1822006-03-23 03:00:21 -080065static DEFINE_MUTEX(controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67struct capi20_appl *capi_applications[CAPI_MAXAPPL];
Jan Kiszka52253032010-02-08 10:12:10 +000068struct capi_ctr *capi_controller[CAPI_MAXCONTR];
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Jan Kiszka52253032010-02-08 10:12:10 +000070static int ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jan Kiszkaef69bb22010-02-08 10:12:13 +000072static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/* -------- controller ref counting -------------------------------------- */
75
76static inline struct capi_ctr *
Jan Kiszka52253032010-02-08 10:12:10 +000077capi_ctr_get(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
Jan Kiszka52253032010-02-08 10:12:10 +000079 if (!try_module_get(ctr->owner))
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 return NULL;
Jan Kiszka52253032010-02-08 10:12:10 +000081 return ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
84static inline void
Jan Kiszka52253032010-02-08 10:12:10 +000085capi_ctr_put(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
Jan Kiszka52253032010-02-08 10:12:10 +000087 module_put(ctr->owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
90/* ------------------------------------------------------------- */
91
92static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
93{
94 if (contr - 1 >= CAPI_MAXCONTR)
95 return NULL;
96
Jan Kiszka52253032010-02-08 10:12:10 +000097 return capi_controller[contr - 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
101{
102 if (applid - 1 >= CAPI_MAXAPPL)
103 return NULL;
104
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168static void notify_up(u32 contr)
169{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 struct capi20_appl *ap;
Jan Kiszka3efecf72010-02-08 10:12:12 +0000171 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 u16 applid;
173
Jan Kiszka3efecf72010-02-08 10:12:12 +0000174 if (showcapimsgs & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000176
177 ctr = get_capi_ctr_by_nr(contr);
178 if (ctr) {
179 if (ctr->state == CAPI_CTR_RUNNING)
180 return;
181
182 ctr->state = CAPI_CTR_RUNNING;
183
184 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
185 ap = get_capi_appl_by_nr(applid);
186 if (!ap || ap->release_in_progress)
187 continue;
188 register_appl(ctr, applid, &ap->rparam);
Jan Kiszka3efecf72010-02-08 10:12:12 +0000189 }
190 } else
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700191 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192}
193
Jan Kiszka3efecf72010-02-08 10:12:12 +0000194static void ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
196 struct capi20_appl *ap;
197 u16 applid;
198
Jan Kiszka3efecf72010-02-08 10:12:12 +0000199 if (ctr->state == CAPI_CTR_DETECTED)
200 return;
201
202 ctr->state = CAPI_CTR_DETECTED;
203
204 memset(ctr->manu, 0, sizeof(ctr->manu));
205 memset(&ctr->version, 0, sizeof(ctr->version));
206 memset(&ctr->profile, 0, sizeof(ctr->profile));
207 memset(ctr->serial, 0, sizeof(ctr->serial));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
210 ap = get_capi_appl_by_nr(applid);
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000211 if (ap && !ap->release_in_progress)
Jan Kiszka3efecf72010-02-08 10:12:12 +0000212 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 }
214}
215
Jan Kiszka3efecf72010-02-08 10:12:12 +0000216static void notify_down(u32 contr)
217{
218 struct capi_ctr *ctr;
219
220 if (showcapimsgs & 1)
221 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
222
223 ctr = get_capi_ctr_by_nr(contr);
224 if (ctr)
225 ctr_down(ctr);
226 else
227 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
228}
229
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000230static int
231notify_handler(struct notifier_block *nb, unsigned long val, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000233 u32 contr = (long)v;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000235 switch (val) {
236 case CAPICTR_UP:
237 notify_up(contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 break;
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000239 case CAPICTR_DOWN:
240 notify_down(contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 break;
242 }
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000243 return NOTIFY_OK;
244}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000246static void do_notify_work(struct work_struct *work)
247{
248 struct capictr_event *event =
249 container_of(work, struct capictr_event, work);
250
251 blocking_notifier_call_chain(&ctr_notifier_list, event->type,
252 (void *)(long)event->controller);
253 kfree(event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254}
255
256/*
257 * The notifier will result in adding/deleteing of devices. Devices can
258 * only removed in user process, not in bh.
259 */
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000260static int notify_push(unsigned int event_type, u32 controller)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000262 struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000264 if (!event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 return -ENOMEM;
266
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000267 INIT_WORK(&event->work, do_notify_work);
268 event->type = event_type;
269 event->controller = controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000271 schedule_work(&event->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 return 0;
273}
274
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000275int register_capictr_notifier(struct notifier_block *nb)
276{
277 return blocking_notifier_chain_register(&ctr_notifier_list, nb);
278}
279EXPORT_SYMBOL_GPL(register_capictr_notifier);
280
281int unregister_capictr_notifier(struct notifier_block *nb)
282{
283 return blocking_notifier_chain_unregister(&ctr_notifier_list, nb);
284}
285EXPORT_SYMBOL_GPL(unregister_capictr_notifier);
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287/* -------- Receiver ------------------------------------------ */
288
David Howellsc4028952006-11-22 14:57:56 +0000289static void recv_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 struct sk_buff *skb;
David Howellsc4028952006-11-22 14:57:56 +0000292 struct capi20_appl *ap =
293 container_of(work, struct capi20_appl, recv_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 if ((!ap) || (ap->release_in_progress))
296 return;
297
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700298 mutex_lock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 while ((skb = skb_dequeue(&ap->recv_queue))) {
300 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
301 ap->nrecvdatapkt++;
302 else
303 ap->nrecvctlpkt++;
304
305 ap->recv_message(ap, skb);
306 }
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700307 mutex_unlock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
309
Tilman Schmidt554f2002009-04-23 02:24:21 +0000310/**
311 * capi_ctr_handle_message() - handle incoming CAPI message
Jan Kiszka52253032010-02-08 10:12:10 +0000312 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000313 * @appl: application ID.
314 * @skb: message.
315 *
316 * Called by hardware driver to pass a CAPI message to the application.
317 */
318
Jan Kiszka52253032010-02-08 10:12:10 +0000319void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
320 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
322 struct capi20_appl *ap;
323 int showctl = 0;
324 u8 cmd, subcmd;
325 unsigned long flags;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800326 _cdebbuf *cdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Jan Kiszka52253032010-02-08 10:12:10 +0000328 if (ctr->state != CAPI_CTR_RUNNING) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800329 cdb = capi_message2str(skb->data);
330 if (cdb) {
331 printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
Jan Kiszka52253032010-02-08 10:12:10 +0000332 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800333 cdebbuf_free(cdb);
334 } else
335 printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000336 ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 goto error;
338 }
339
340 cmd = CAPIMSG_COMMAND(skb->data);
341 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
342 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
Jan Kiszka52253032010-02-08 10:12:10 +0000343 ctr->nrecvdatapkt++;
344 if (ctr->traceflag > 2)
345 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000347 ctr->nrecvctlpkt++;
348 if (ctr->traceflag)
349 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
Jan Kiszka52253032010-02-08 10:12:10 +0000351 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (showctl & 2) {
353 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800354 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000355 ctr->cnr, CAPIMSG_APPID(skb->data),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 capi_cmd2str(cmd, subcmd),
357 CAPIMSG_LEN(skb->data));
358 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800359 cdb = capi_message2str(skb->data);
360 if (cdb) {
361 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000362 ctr->cnr, cdb->buf);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800363 cdebbuf_free(cdb);
364 } else
365 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
Jan Kiszka52253032010-02-08 10:12:10 +0000366 ctr->cnr, CAPIMSG_APPID(skb->data),
Karsten Keil17f0cd22007-02-28 20:13:50 -0800367 capi_cmd2str(cmd, subcmd),
368 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
370
371 }
372
373 read_lock_irqsave(&application_lock, flags);
374 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
375 if ((!ap) || (ap->release_in_progress)) {
376 read_unlock_irqrestore(&application_lock, flags);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800377 cdb = capi_message2str(skb->data);
378 if (cdb) {
379 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
380 CAPIMSG_APPID(skb->data), cdb->buf);
381 cdebbuf_free(cdb);
382 } else
383 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
384 CAPIMSG_APPID(skb->data),
385 capi_cmd2str(cmd, subcmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 goto error;
387 }
388 skb_queue_tail(&ap->recv_queue, skb);
389 schedule_work(&ap->recv_work);
390 read_unlock_irqrestore(&application_lock, flags);
391
392 return;
393
394error:
395 kfree_skb(skb);
396}
397
398EXPORT_SYMBOL(capi_ctr_handle_message);
399
Tilman Schmidt554f2002009-04-23 02:24:21 +0000400/**
401 * capi_ctr_ready() - signal CAPI controller ready
Jan Kiszka52253032010-02-08 10:12:10 +0000402 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000403 *
404 * Called by hardware driver to signal that the controller is up and running.
405 */
406
Jan Kiszka52253032010-02-08 10:12:10 +0000407void capi_ctr_ready(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
Jan Kiszka52253032010-02-08 10:12:10 +0000409 printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
410 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000412 notify_push(CAPICTR_UP, ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415EXPORT_SYMBOL(capi_ctr_ready);
416
Tilman Schmidt554f2002009-04-23 02:24:21 +0000417/**
Tilman Schmidt4e329972009-06-07 09:09:23 +0000418 * capi_ctr_down() - signal CAPI controller not ready
Jan Kiszka52253032010-02-08 10:12:10 +0000419 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000420 *
421 * Called by hardware driver to signal that the controller is down and
422 * unavailable for use.
423 */
424
Jan Kiszka52253032010-02-08 10:12:10 +0000425void capi_ctr_down(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Jan Kiszka52253032010-02-08 10:12:10 +0000427 printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Jan Kiszkaef69bb22010-02-08 10:12:13 +0000429 notify_push(CAPICTR_DOWN, ctr->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430}
431
Tilman Schmidt4e329972009-06-07 09:09:23 +0000432EXPORT_SYMBOL(capi_ctr_down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Tilman Schmidt554f2002009-04-23 02:24:21 +0000434/**
435 * capi_ctr_suspend_output() - suspend controller
Jan Kiszka52253032010-02-08 10:12:10 +0000436 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000437 *
438 * Called by hardware driver to stop data flow.
439 */
440
Jan Kiszka52253032010-02-08 10:12:10 +0000441void capi_ctr_suspend_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Jan Kiszka52253032010-02-08 10:12:10 +0000443 if (!ctr->blocked) {
444 printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
445 ctr->cnr);
446 ctr->blocked = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
448}
449
450EXPORT_SYMBOL(capi_ctr_suspend_output);
451
Tilman Schmidt554f2002009-04-23 02:24:21 +0000452/**
453 * capi_ctr_resume_output() - resume controller
Jan Kiszka52253032010-02-08 10:12:10 +0000454 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000455 *
456 * Called by hardware driver to resume data flow.
457 */
458
Jan Kiszka52253032010-02-08 10:12:10 +0000459void capi_ctr_resume_output(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Jan Kiszka52253032010-02-08 10:12:10 +0000461 if (ctr->blocked) {
462 printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
463 ctr->cnr);
464 ctr->blocked = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466}
467
468EXPORT_SYMBOL(capi_ctr_resume_output);
469
470/* ------------------------------------------------------------- */
471
Tilman Schmidt554f2002009-04-23 02:24:21 +0000472/**
473 * attach_capi_ctr() - register CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000474 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000475 *
476 * Called by hardware driver to register a controller with the CAPI subsystem.
477 * Return value: 0 on success, error code < 0 on error
478 */
479
Jan Kiszka52253032010-02-08 10:12:10 +0000480int attach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
482 int i;
483
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800484 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000487 if (!capi_controller[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 break;
489 }
490 if (i == CAPI_MAXCONTR) {
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800491 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 printk(KERN_ERR "kcapi: out of controller slots\n");
493 return -EBUSY;
494 }
Jan Kiszka52253032010-02-08 10:12:10 +0000495 capi_controller[i] = ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800497 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
Jan Kiszka52253032010-02-08 10:12:10 +0000499 ctr->nrecvctlpkt = 0;
500 ctr->nrecvdatapkt = 0;
501 ctr->nsentctlpkt = 0;
502 ctr->nsentdatapkt = 0;
503 ctr->cnr = i + 1;
504 ctr->state = CAPI_CTR_DETECTED;
505 ctr->blocked = 0;
506 ctr->traceflag = showcapimsgs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Jan Kiszka52253032010-02-08 10:12:10 +0000508 sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
509 ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Jan Kiszka52253032010-02-08 10:12:10 +0000511 ncontrollers++;
512 printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
513 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 return 0;
515}
516
517EXPORT_SYMBOL(attach_capi_ctr);
518
Tilman Schmidt554f2002009-04-23 02:24:21 +0000519/**
520 * detach_capi_ctr() - unregister CAPI controller
Jan Kiszka52253032010-02-08 10:12:10 +0000521 * @ctr: controller descriptor structure.
Tilman Schmidt554f2002009-04-23 02:24:21 +0000522 *
523 * Called by hardware driver to remove the registration of a controller
524 * with the CAPI subsystem.
525 * Return value: 0 on success, error code < 0 on error
526 */
527
Jan Kiszka52253032010-02-08 10:12:10 +0000528int detach_capi_ctr(struct capi_ctr *ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
Jan Kiszka3efecf72010-02-08 10:12:12 +0000530 ctr_down(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Jan Kiszka52253032010-02-08 10:12:10 +0000532 ncontrollers--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Jan Kiszka52253032010-02-08 10:12:10 +0000534 if (ctr->procent) {
535 remove_proc_entry(ctr->procfn, NULL);
536 ctr->procent = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
Jan Kiszka52253032010-02-08 10:12:10 +0000538 capi_controller[ctr->cnr - 1] = NULL;
539 printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
540 ctr->cnr, ctr->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 return 0;
543}
544
545EXPORT_SYMBOL(detach_capi_ctr);
546
Tilman Schmidt554f2002009-04-23 02:24:21 +0000547/**
548 * register_capi_driver() - register CAPI driver
549 * @driver: driver descriptor structure.
550 *
551 * Called by hardware driver to register itself with the CAPI subsystem.
552 */
553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554void register_capi_driver(struct capi_driver *driver)
555{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000556 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 list_add_tail(&driver->list, &capi_drivers);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000558 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
561EXPORT_SYMBOL(register_capi_driver);
562
Tilman Schmidt554f2002009-04-23 02:24:21 +0000563/**
564 * unregister_capi_driver() - unregister CAPI driver
565 * @driver: driver descriptor structure.
566 *
567 * Called by hardware driver to unregister itself from the CAPI subsystem.
568 */
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570void unregister_capi_driver(struct capi_driver *driver)
571{
Jan Kiszka9717fb82010-02-08 10:12:11 +0000572 mutex_lock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 list_del(&driver->list);
Jan Kiszka9717fb82010-02-08 10:12:11 +0000574 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
577EXPORT_SYMBOL(unregister_capi_driver);
578
579/* ------------------------------------------------------------- */
580/* -------- CAPI2.0 Interface ---------------------------------- */
581/* ------------------------------------------------------------- */
582
Tilman Schmidt554f2002009-04-23 02:24:21 +0000583/**
584 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
585 *
586 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
587 * is ready for use, CAPI_REGNOTINSTALLED otherwise)
588 */
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590u16 capi20_isinstalled(void)
591{
592 int i;
593 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000594 if (capi_controller[i] &&
595 capi_controller[i]->state == CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 return CAPI_NOERROR;
597 }
598 return CAPI_REGNOTINSTALLED;
599}
600
601EXPORT_SYMBOL(capi20_isinstalled);
602
Tilman Schmidt554f2002009-04-23 02:24:21 +0000603/**
604 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
605 * @ap: CAPI application descriptor structure.
606 *
607 * Register an application's presence with CAPI.
608 * A unique application ID is assigned and stored in @ap->applid.
609 * After this function returns successfully, the message receive
610 * callback function @ap->recv_message() may be called at any time
611 * until capi20_release() has been called for the same @ap.
612 * Return value: CAPI result code
613 */
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615u16 capi20_register(struct capi20_appl *ap)
616{
617 int i;
618 u16 applid;
619 unsigned long flags;
620
621 DBG("");
622
623 if (ap->rparam.datablklen < 128)
624 return CAPI_LOGBLKSIZETOSMALL;
625
626 write_lock_irqsave(&application_lock, flags);
627
628 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
629 if (capi_applications[applid - 1] == NULL)
630 break;
631 }
632 if (applid > CAPI_MAXAPPL) {
633 write_unlock_irqrestore(&application_lock, flags);
634 return CAPI_TOOMANYAPPLS;
635 }
636
637 ap->applid = applid;
638 capi_applications[applid - 1] = ap;
639
640 ap->nrecvctlpkt = 0;
641 ap->nrecvdatapkt = 0;
642 ap->nsentctlpkt = 0;
643 ap->nsentdatapkt = 0;
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700644 mutex_init(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 skb_queue_head_init(&ap->recv_queue);
David Howellsc4028952006-11-22 14:57:56 +0000646 INIT_WORK(&ap->recv_work, recv_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 ap->release_in_progress = 0;
648
649 write_unlock_irqrestore(&application_lock, flags);
650
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800651 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000653 if (!capi_controller[i] ||
654 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000656 register_appl(capi_controller[i], applid, &ap->rparam);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800658 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 if (showcapimsgs & 1) {
661 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
662 }
663
664 return CAPI_NOERROR;
665}
666
667EXPORT_SYMBOL(capi20_register);
668
Tilman Schmidt554f2002009-04-23 02:24:21 +0000669/**
670 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
671 * @ap: CAPI application descriptor structure.
672 *
673 * Terminate an application's registration with CAPI.
674 * After this function returns successfully, the message receive
675 * callback function @ap->recv_message() will no longer be called.
676 * Return value: CAPI result code
677 */
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679u16 capi20_release(struct capi20_appl *ap)
680{
681 int i;
682 unsigned long flags;
683
684 DBG("applid %#x", ap->applid);
685
686 write_lock_irqsave(&application_lock, flags);
687 ap->release_in_progress = 1;
688 capi_applications[ap->applid - 1] = NULL;
689 write_unlock_irqrestore(&application_lock, flags);
690
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800691 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 for (i = 0; i < CAPI_MAXCONTR; i++) {
Jan Kiszka52253032010-02-08 10:12:10 +0000693 if (!capi_controller[i] ||
694 capi_controller[i]->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 continue;
Jan Kiszka52253032010-02-08 10:12:10 +0000696 release_appl(capi_controller[i], ap->applid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800698 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700 flush_scheduled_work();
701 skb_queue_purge(&ap->recv_queue);
702
703 if (showcapimsgs & 1) {
704 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
705 }
706
707 return CAPI_NOERROR;
708}
709
710EXPORT_SYMBOL(capi20_release);
711
Tilman Schmidt554f2002009-04-23 02:24:21 +0000712/**
713 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
714 * @ap: CAPI application descriptor structure.
715 * @skb: CAPI message.
716 *
717 * Transfer a single message to CAPI.
718 * Return value: CAPI result code
719 */
720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
722{
Jan Kiszka52253032010-02-08 10:12:10 +0000723 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 int showctl = 0;
725 u8 cmd, subcmd;
726
727 DBG("applid %#x", ap->applid);
728
Jan Kiszka52253032010-02-08 10:12:10 +0000729 if (ncontrollers == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return CAPI_REGNOTINSTALLED;
731 if ((ap->applid == 0) || ap->release_in_progress)
732 return CAPI_ILLAPPNR;
733 if (skb->len < 12
734 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
735 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
736 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
Jan Kiszka52253032010-02-08 10:12:10 +0000737 ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
738 if (!ctr || ctr->state != CAPI_CTR_RUNNING) {
739 ctr = get_capi_ctr_by_nr(1); /* XXX why? */
740 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return CAPI_REGNOTINSTALLED;
742 }
Jan Kiszka52253032010-02-08 10:12:10 +0000743 if (ctr->blocked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return CAPI_SENDQUEUEFULL;
745
746 cmd = CAPIMSG_COMMAND(skb->data);
747 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
748
749 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
Jan Kiszka52253032010-02-08 10:12:10 +0000750 ctr->nsentdatapkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 ap->nsentdatapkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000752 if (ctr->traceflag > 2)
753 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 } else {
Jan Kiszka52253032010-02-08 10:12:10 +0000755 ctr->nsentctlpkt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 ap->nsentctlpkt++;
Jan Kiszka52253032010-02-08 10:12:10 +0000757 if (ctr->traceflag)
758 showctl |= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
Jan Kiszka52253032010-02-08 10:12:10 +0000760 showctl |= (ctr->traceflag & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 if (showctl & 2) {
762 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800763 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 CAPIMSG_CONTROLLER(skb->data),
765 CAPIMSG_APPID(skb->data),
766 capi_cmd2str(cmd, subcmd),
767 CAPIMSG_LEN(skb->data));
768 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800769 _cdebbuf *cdb = capi_message2str(skb->data);
770 if (cdb) {
771 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
772 CAPIMSG_CONTROLLER(skb->data),
773 cdb->buf);
774 cdebbuf_free(cdb);
775 } else
776 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
777 CAPIMSG_CONTROLLER(skb->data),
778 CAPIMSG_APPID(skb->data),
779 capi_cmd2str(cmd, subcmd),
780 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
Jan Kiszka52253032010-02-08 10:12:10 +0000783 return ctr->send_message(ctr, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784}
785
786EXPORT_SYMBOL(capi20_put_message);
787
Tilman Schmidt554f2002009-04-23 02:24:21 +0000788/**
789 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
790 * @contr: controller number.
791 * @buf: result buffer (64 bytes).
792 *
793 * Retrieve information about the manufacturer of the specified ISDN controller
794 * or (for @contr == 0) the driver itself.
795 * Return value: CAPI result code
796 */
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798u16 capi20_get_manufacturer(u32 contr, u8 *buf)
799{
Jan Kiszka52253032010-02-08 10:12:10 +0000800 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if (contr == 0) {
803 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
804 return CAPI_NOERROR;
805 }
Jan Kiszka52253032010-02-08 10:12:10 +0000806 ctr = get_capi_ctr_by_nr(contr);
807 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return CAPI_REGNOTINSTALLED;
Jan Kiszka52253032010-02-08 10:12:10 +0000809 strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return CAPI_NOERROR;
811}
812
813EXPORT_SYMBOL(capi20_get_manufacturer);
814
Tilman Schmidt554f2002009-04-23 02:24:21 +0000815/**
816 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
817 * @contr: controller number.
818 * @verp: result structure.
819 *
820 * Retrieve version information for the specified ISDN controller
821 * or (for @contr == 0) the driver itself.
822 * Return value: CAPI result code
823 */
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825u16 capi20_get_version(u32 contr, struct capi_version *verp)
826{
Jan Kiszka52253032010-02-08 10:12:10 +0000827 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 if (contr == 0) {
830 *verp = driver_version;
831 return CAPI_NOERROR;
832 }
Jan Kiszka52253032010-02-08 10:12:10 +0000833 ctr = get_capi_ctr_by_nr(contr);
834 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return CAPI_REGNOTINSTALLED;
836
Jan Kiszka52253032010-02-08 10:12:10 +0000837 memcpy(verp, &ctr->version, sizeof(capi_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 return CAPI_NOERROR;
839}
840
841EXPORT_SYMBOL(capi20_get_version);
842
Tilman Schmidt554f2002009-04-23 02:24:21 +0000843/**
844 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
845 * @contr: controller number.
846 * @serial: result buffer (8 bytes).
847 *
848 * Retrieve the serial number of the specified ISDN controller
849 * or (for @contr == 0) the driver itself.
850 * Return value: CAPI result code
851 */
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853u16 capi20_get_serial(u32 contr, u8 *serial)
854{
Jan Kiszka52253032010-02-08 10:12:10 +0000855 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 if (contr == 0) {
858 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
859 return CAPI_NOERROR;
860 }
Jan Kiszka52253032010-02-08 10:12:10 +0000861 ctr = get_capi_ctr_by_nr(contr);
862 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return CAPI_REGNOTINSTALLED;
864
Jan Kiszka52253032010-02-08 10:12:10 +0000865 strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return CAPI_NOERROR;
867}
868
869EXPORT_SYMBOL(capi20_get_serial);
870
Tilman Schmidt554f2002009-04-23 02:24:21 +0000871/**
872 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
873 * @contr: controller number.
874 * @profp: result structure.
875 *
876 * Retrieve capability information for the specified ISDN controller
877 * or (for @contr == 0) the number of installed controllers.
878 * Return value: CAPI result code
879 */
880
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
882{
Jan Kiszka52253032010-02-08 10:12:10 +0000883 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 if (contr == 0) {
Jan Kiszka52253032010-02-08 10:12:10 +0000886 profp->ncontroller = ncontrollers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return CAPI_NOERROR;
888 }
Jan Kiszka52253032010-02-08 10:12:10 +0000889 ctr = get_capi_ctr_by_nr(contr);
890 if (!ctr || ctr->state != CAPI_CTR_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return CAPI_REGNOTINSTALLED;
892
Jan Kiszka52253032010-02-08 10:12:10 +0000893 memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return CAPI_NOERROR;
895}
896
897EXPORT_SYMBOL(capi20_get_profile);
898
Robert P. J. Day37772ac2008-04-28 02:14:42 -0700899#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900static int old_capi_manufacturer(unsigned int cmd, void __user *data)
901{
902 avmb1_loadandconfigdef ldef;
903 avmb1_extcarddef cdef;
904 avmb1_resetdef rdef;
905 capicardparams cparams;
Jan Kiszka52253032010-02-08 10:12:10 +0000906 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 struct capi_driver *driver = NULL;
908 capiloaddata ldata;
909 struct list_head *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 int retval;
911
912 switch (cmd) {
913 case AVMB1_ADDCARD:
914 case AVMB1_ADDCARD_WITH_TYPE:
915 if (cmd == AVMB1_ADDCARD) {
916 if ((retval = copy_from_user(&cdef, data,
917 sizeof(avmb1_carddef))))
918 return retval;
919 cdef.cardtype = AVM_CARDTYPE_B1;
920 } else {
921 if ((retval = copy_from_user(&cdef, data,
922 sizeof(avmb1_extcarddef))))
923 return retval;
924 }
925 cparams.port = cdef.port;
926 cparams.irq = cdef.irq;
927 cparams.cardnr = cdef.cardnr;
928
Jan Kiszka9717fb82010-02-08 10:12:11 +0000929 mutex_lock(&capi_drivers_lock);
930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 switch (cdef.cardtype) {
932 case AVM_CARDTYPE_B1:
933 list_for_each(l, &capi_drivers) {
934 driver = list_entry(l, struct capi_driver, list);
935 if (strcmp(driver->name, "b1isa") == 0)
936 break;
937 }
938 break;
939 case AVM_CARDTYPE_T1:
940 list_for_each(l, &capi_drivers) {
941 driver = list_entry(l, struct capi_driver, list);
942 if (strcmp(driver->name, "t1isa") == 0)
943 break;
944 }
945 break;
946 default:
947 driver = NULL;
948 break;
949 }
950 if (!driver) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 printk(KERN_ERR "kcapi: driver not loaded.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000952 retval = -EIO;
953 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 printk(KERN_ERR "kcapi: driver has no add card function.\n");
Jan Kiszka9717fb82010-02-08 10:12:11 +0000955 retval = -EIO;
956 } else
957 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Jan Kiszka9717fb82010-02-08 10:12:11 +0000959 mutex_unlock(&capi_drivers_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return retval;
961
962 case AVMB1_LOAD:
963 case AVMB1_LOAD_AND_CONFIG:
964
965 if (cmd == AVMB1_LOAD) {
966 if (copy_from_user(&ldef, data,
967 sizeof(avmb1_loaddef)))
968 return -EFAULT;
969 ldef.t4config.len = 0;
970 ldef.t4config.data = NULL;
971 } else {
972 if (copy_from_user(&ldef, data,
973 sizeof(avmb1_loadandconfigdef)))
974 return -EFAULT;
975 }
Jan Kiszka52253032010-02-08 10:12:10 +0000976 ctr = get_capi_ctr_by_nr(ldef.contr);
977 if (!ctr)
Jesper Juhle8a285b2007-10-16 01:27:52 -0700978 return -EINVAL;
Jan Kiszka52253032010-02-08 10:12:10 +0000979 ctr = capi_ctr_get(ctr);
980 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return -ESRCH;
Jan Kiszka52253032010-02-08 10:12:10 +0000982 if (ctr->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 printk(KERN_DEBUG "kcapi: load: no load function\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000984 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return -ESRCH;
986 }
987
988 if (ldef.t4file.len <= 0) {
989 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Jan Kiszka52253032010-02-08 10:12:10 +0000990 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return -EINVAL;
992 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -0700993 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Jan Kiszka52253032010-02-08 10:12:10 +0000995 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return -EINVAL;
997 }
998
999 ldata.firmware.user = 1;
1000 ldata.firmware.data = ldef.t4file.data;
1001 ldata.firmware.len = ldef.t4file.len;
1002 ldata.configuration.user = 1;
1003 ldata.configuration.data = ldef.t4config.data;
1004 ldata.configuration.len = ldef.t4config.len;
1005
Jan Kiszka52253032010-02-08 10:12:10 +00001006 if (ctr->state != CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Jan Kiszka52253032010-02-08 10:12:10 +00001008 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return -EBUSY;
1010 }
Jan Kiszka52253032010-02-08 10:12:10 +00001011 ctr->state = CAPI_CTR_LOADING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Jan Kiszka52253032010-02-08 10:12:10 +00001013 retval = ctr->load_firmware(ctr, &ldata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 if (retval) {
Jan Kiszka52253032010-02-08 10:12:10 +00001016 ctr->state = CAPI_CTR_DETECTED;
1017 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return retval;
1019 }
1020
Jan Kiszka52253032010-02-08 10:12:10 +00001021 while (ctr->state != CAPI_CTR_RUNNING) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 msleep_interruptible(100); /* 0.1 sec */
1024
1025 if (signal_pending(current)) {
Jan Kiszka52253032010-02-08 10:12:10 +00001026 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return -EINTR;
1028 }
1029 }
Jan Kiszka52253032010-02-08 10:12:10 +00001030 capi_ctr_put(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
1032
1033 case AVMB1_RESETCARD:
1034 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1035 return -EFAULT;
Jan Kiszka52253032010-02-08 10:12:10 +00001036 ctr = get_capi_ctr_by_nr(rdef.contr);
1037 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return -ESRCH;
1039
Jan Kiszka52253032010-02-08 10:12:10 +00001040 if (ctr->state == CAPI_CTR_DETECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 return 0;
1042
Jan Kiszka52253032010-02-08 10:12:10 +00001043 ctr->reset_ctr(ctr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Jan Kiszka52253032010-02-08 10:12:10 +00001045 while (ctr->state > CAPI_CTR_DETECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 msleep_interruptible(100); /* 0.1 sec */
1048
1049 if (signal_pending(current))
1050 return -EINTR;
1051 }
1052 return 0;
1053
1054 }
1055 return -EINVAL;
1056}
1057#endif
1058
Tilman Schmidt554f2002009-04-23 02:24:21 +00001059/**
1060 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1061 * @cmd: command.
1062 * @data: parameter.
1063 *
1064 * Perform manufacturer specific command.
1065 * Return value: CAPI result code
1066 */
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068int capi20_manufacturer(unsigned int cmd, void __user *data)
1069{
Jan Kiszka52253032010-02-08 10:12:10 +00001070 struct capi_ctr *ctr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001073#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 case AVMB1_LOAD:
1075 case AVMB1_LOAD_AND_CONFIG:
1076 case AVMB1_RESETCARD:
1077 case AVMB1_GET_CARDINFO:
1078 case AVMB1_REMOVECARD:
1079 return old_capi_manufacturer(cmd, data);
1080#endif
1081 case KCAPI_CMD_TRACE:
1082 {
1083 kcapi_flagdef fdef;
1084
1085 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1086 return -EFAULT;
1087
Jan Kiszka52253032010-02-08 10:12:10 +00001088 ctr = get_capi_ctr_by_nr(fdef.contr);
1089 if (!ctr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return -ESRCH;
1091
Jan Kiszka52253032010-02-08 10:12:10 +00001092 ctr->traceflag = fdef.flag;
Karsten Keil17f0cd22007-02-28 20:13:50 -08001093 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
Jan Kiszka52253032010-02-08 10:12:10 +00001094 ctr->cnr, ctr->traceflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return 0;
1096 }
1097 case KCAPI_CMD_ADDCARD:
1098 {
1099 struct list_head *l;
1100 struct capi_driver *driver = NULL;
1101 capicardparams cparams;
1102 kcapi_carddef cdef;
1103 int retval;
1104
1105 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1106 return retval;
1107
1108 cparams.port = cdef.port;
1109 cparams.irq = cdef.irq;
1110 cparams.membase = cdef.membase;
1111 cparams.cardnr = cdef.cardnr;
1112 cparams.cardtype = 0;
1113 cdef.driver[sizeof(cdef.driver)-1] = 0;
1114
Jan Kiszka9717fb82010-02-08 10:12:11 +00001115 mutex_lock(&capi_drivers_lock);
1116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 list_for_each(l, &capi_drivers) {
1118 driver = list_entry(l, struct capi_driver, list);
1119 if (strcmp(driver->name, cdef.driver) == 0)
1120 break;
1121 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001122 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1124 cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001125 retval = -ESRCH;
1126 } else if (!driver->add_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
Jan Kiszka9717fb82010-02-08 10:12:11 +00001128 retval = -EIO;
1129 } else
1130 retval = driver->add_card(driver, &cparams);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Jan Kiszka9717fb82010-02-08 10:12:11 +00001132 mutex_unlock(&capi_drivers_lock);
1133 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
1135
1136 default:
1137 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1138 cmd);
1139 break;
1140
1141 }
1142 return -EINVAL;
1143}
1144
1145EXPORT_SYMBOL(capi20_manufacturer);
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147/* ------------------------------------------------------------- */
1148/* -------- Init & Cleanup ------------------------------------- */
1149/* ------------------------------------------------------------- */
1150
1151/*
1152 * init / exit functions
1153 */
1154
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001155static struct notifier_block capictr_nb = {
1156 .notifier_call = notify_handler,
1157 .priority = INT_MAX,
1158};
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160static int __init kcapi_init(void)
1161{
Jan Kiszka88549d62010-02-08 10:12:09 +00001162 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Jan Kiszkaef69bb22010-02-08 10:12:13 +00001164 register_capictr_notifier(&capictr_nb);
1165
Jan Kiszka88549d62010-02-08 10:12:09 +00001166 err = cdebug_init();
1167 if (!err)
1168 kcapi_proc_init();
1169 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170}
1171
1172static void __exit kcapi_exit(void)
1173{
1174 kcapi_proc_exit();
1175
1176 /* make sure all notifiers are finished */
1177 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001178 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179}
1180
1181module_init(kcapi_init);
1182module_exit(kcapi_exit);