11da177e4SLinus Torvalds /* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
21da177e4SLinus Torvalds *
31da177e4SLinus Torvalds * Kernel CAPI 2.0 Module
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright 1999 by Carsten Paeth <calle@calle.de>
61da177e4SLinus Torvalds * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * This software may be used and distributed according to the terms
91da177e4SLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include "kcapi.h"
141da177e4SLinus Torvalds #include <linux/module.h>
151da177e4SLinus Torvalds #include <linux/mm.h>
161da177e4SLinus Torvalds #include <linux/interrupt.h>
171da177e4SLinus Torvalds #include <linux/ioport.h>
181da177e4SLinus Torvalds #include <linux/proc_fs.h>
19174cd4b1SIngo Molnar #include <linux/sched/signal.h>
201da177e4SLinus Torvalds #include <linux/seq_file.h>
211da177e4SLinus Torvalds #include <linux/skbuff.h>
221da177e4SLinus Torvalds #include <linux/workqueue.h>
231da177e4SLinus Torvalds #include <linux/capi.h>
241da177e4SLinus Torvalds #include <linux/kernelcapi.h>
251da177e4SLinus Torvalds #include <linux/init.h>
261da177e4SLinus Torvalds #include <linux/moduleparam.h>
271da177e4SLinus Torvalds #include <linux/delay.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
301da177e4SLinus Torvalds #include <linux/isdn/capicmd.h>
311da177e4SLinus Torvalds #include <linux/isdn/capiutil.h>
329cdf1827SArjan van de Ven #include <linux/mutex.h>
3388c896efSJan Kiszka #include <linux/rcupdate.h>
341da177e4SLinus Torvalds
352cd24a2eSJason Wang static int showcapimsgs;
36158fa677STejun Heo static struct workqueue_struct *kcapi_wq;
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds module_param(showcapimsgs, uint, 0);
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds /* ------------------------------------------------------------- */
411da177e4SLinus Torvalds
42ef69bb2eSJan Kiszka struct capictr_event {
431da177e4SLinus Torvalds struct work_struct work;
44ef69bb2eSJan Kiszka unsigned int type;
451da177e4SLinus Torvalds u32 controller;
461da177e4SLinus Torvalds };
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds /* ------------------------------------------------------------- */
491da177e4SLinus Torvalds
50733a707dSBhumika Goyal static const struct capi_version driver_version = {2, 0, 1, 1 << 4};
511da177e4SLinus Torvalds static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
521da177e4SLinus Torvalds static char capi_manufakturer[64] = "AVM Berlin";
531da177e4SLinus Torvalds
541da177e4SLinus Torvalds #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
551da177e4SLinus Torvalds
560ca3a017SJan Kiszka struct capi_ctr *capi_controller[CAPI_MAXCONTR];
570ca3a017SJan Kiszka DEFINE_MUTEX(capi_controller_lock);
580ca3a017SJan Kiszka
591da177e4SLinus Torvalds struct capi20_appl *capi_applications[CAPI_MAXAPPL];
601da177e4SLinus Torvalds
6152253031SJan Kiszka static int ncontrollers;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds /* -------- controller ref counting -------------------------------------- */
641da177e4SLinus Torvalds
651da177e4SLinus Torvalds static inline struct capi_ctr *
capi_ctr_get(struct capi_ctr * ctr)6652253031SJan Kiszka capi_ctr_get(struct capi_ctr *ctr)
671da177e4SLinus Torvalds {
6852253031SJan Kiszka if (!try_module_get(ctr->owner))
691da177e4SLinus Torvalds return NULL;
7052253031SJan Kiszka return ctr;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds static inline void
capi_ctr_put(struct capi_ctr * ctr)7452253031SJan Kiszka capi_ctr_put(struct capi_ctr *ctr)
751da177e4SLinus Torvalds {
7652253031SJan Kiszka module_put(ctr->owner);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds /* ------------------------------------------------------------- */
801da177e4SLinus Torvalds
get_capi_ctr_by_nr(u16 contr)811da177e4SLinus Torvalds static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
821da177e4SLinus Torvalds {
8325dff94fSDan Carpenter if (contr < 1 || contr - 1 >= CAPI_MAXCONTR)
841da177e4SLinus Torvalds return NULL;
851da177e4SLinus Torvalds
8652253031SJan Kiszka return capi_controller[contr - 1];
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds
__get_capi_appl_by_nr(u16 applid)89b003f4e1SJan Kiszka static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid)
90b003f4e1SJan Kiszka {
91b003f4e1SJan Kiszka lockdep_assert_held(&capi_controller_lock);
92b003f4e1SJan Kiszka
9325dff94fSDan Carpenter if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
94b003f4e1SJan Kiszka return NULL;
95b003f4e1SJan Kiszka
96b003f4e1SJan Kiszka return capi_applications[applid - 1];
97b003f4e1SJan Kiszka }
98b003f4e1SJan Kiszka
get_capi_appl_by_nr(u16 applid)991da177e4SLinus Torvalds static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
1001da177e4SLinus Torvalds {
10125dff94fSDan Carpenter if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
1021da177e4SLinus Torvalds return NULL;
1031da177e4SLinus Torvalds
10488c896efSJan Kiszka return rcu_dereference(capi_applications[applid - 1]);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds /* -------- util functions ------------------------------------ */
1081da177e4SLinus Torvalds
capi_cmd_valid(u8 cmd)1091da177e4SLinus Torvalds static inline int capi_cmd_valid(u8 cmd)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds switch (cmd) {
1121da177e4SLinus Torvalds case CAPI_ALERT:
1131da177e4SLinus Torvalds case CAPI_CONNECT:
1141da177e4SLinus Torvalds case CAPI_CONNECT_ACTIVE:
1151da177e4SLinus Torvalds case CAPI_CONNECT_B3_ACTIVE:
1161da177e4SLinus Torvalds case CAPI_CONNECT_B3:
1171da177e4SLinus Torvalds case CAPI_CONNECT_B3_T90_ACTIVE:
1181da177e4SLinus Torvalds case CAPI_DATA_B3:
1191da177e4SLinus Torvalds case CAPI_DISCONNECT_B3:
1201da177e4SLinus Torvalds case CAPI_DISCONNECT:
1211da177e4SLinus Torvalds case CAPI_FACILITY:
1221da177e4SLinus Torvalds case CAPI_INFO:
1231da177e4SLinus Torvalds case CAPI_LISTEN:
1241da177e4SLinus Torvalds case CAPI_MANUFACTURER:
1251da177e4SLinus Torvalds case CAPI_RESET_B3:
1261da177e4SLinus Torvalds case CAPI_SELECT_B_PROTOCOL:
1271da177e4SLinus Torvalds return 1;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds return 0;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds
capi_subcmd_valid(u8 subcmd)1321da177e4SLinus Torvalds static inline int capi_subcmd_valid(u8 subcmd)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds switch (subcmd) {
1351da177e4SLinus Torvalds case CAPI_REQ:
1361da177e4SLinus Torvalds case CAPI_CONF:
1371da177e4SLinus Torvalds case CAPI_IND:
1381da177e4SLinus Torvalds case CAPI_RESP:
1391da177e4SLinus Torvalds return 1;
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds return 0;
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds /* ------------------------------------------------------------ */
1451da177e4SLinus Torvalds
14652253031SJan Kiszka static void
register_appl(struct capi_ctr * ctr,u16 applid,capi_register_params * rparam)14752253031SJan Kiszka register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam)
1481da177e4SLinus Torvalds {
14952253031SJan Kiszka ctr = capi_ctr_get(ctr);
1501da177e4SLinus Torvalds
15152253031SJan Kiszka if (ctr)
15252253031SJan Kiszka ctr->register_appl(ctr, applid, rparam);
1531da177e4SLinus Torvalds else
15452253031SJan Kiszka printk(KERN_WARNING "%s: cannot get controller resources\n",
15552253031SJan Kiszka __func__);
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds
release_appl(struct capi_ctr * ctr,u16 applid)15952253031SJan Kiszka static void release_appl(struct capi_ctr *ctr, u16 applid)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds DBG("applid %#x", applid);
1621da177e4SLinus Torvalds
16352253031SJan Kiszka ctr->release_appl(ctr, applid);
16452253031SJan Kiszka capi_ctr_put(ctr);
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds
notify_up(u32 contr)1671da177e4SLinus Torvalds static void notify_up(u32 contr)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds struct capi20_appl *ap;
1703efecf7aSJan Kiszka struct capi_ctr *ctr;
1711da177e4SLinus Torvalds u16 applid;
1721da177e4SLinus Torvalds
1730ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
1740ca3a017SJan Kiszka
1753efecf7aSJan Kiszka if (showcapimsgs & 1)
1761da177e4SLinus Torvalds printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
1773efecf7aSJan Kiszka
1783efecf7aSJan Kiszka ctr = get_capi_ctr_by_nr(contr);
1793efecf7aSJan Kiszka if (ctr) {
1803efecf7aSJan Kiszka if (ctr->state == CAPI_CTR_RUNNING)
1810ca3a017SJan Kiszka goto unlock_out;
1823efecf7aSJan Kiszka
1833efecf7aSJan Kiszka ctr->state = CAPI_CTR_RUNNING;
1843efecf7aSJan Kiszka
1851da177e4SLinus Torvalds for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
186b003f4e1SJan Kiszka ap = __get_capi_appl_by_nr(applid);
187b003f4e1SJan Kiszka if (ap)
18852253031SJan Kiszka register_appl(ctr, applid, &ap->rparam);
1891da177e4SLinus Torvalds }
1903efecf7aSJan Kiszka } else
1913efecf7aSJan Kiszka printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
1920ca3a017SJan Kiszka
1930ca3a017SJan Kiszka unlock_out:
1940ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds
ctr_down(struct capi_ctr * ctr,int new_state)1970ca3a017SJan Kiszka static void ctr_down(struct capi_ctr *ctr, int new_state)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds struct capi20_appl *ap;
2001da177e4SLinus Torvalds u16 applid;
2011da177e4SLinus Torvalds
2020ca3a017SJan Kiszka if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED)
2033efecf7aSJan Kiszka return;
2043efecf7aSJan Kiszka
2050ca3a017SJan Kiszka ctr->state = new_state;
2063efecf7aSJan Kiszka
2073efecf7aSJan Kiszka memset(ctr->manu, 0, sizeof(ctr->manu));
2083efecf7aSJan Kiszka memset(&ctr->version, 0, sizeof(ctr->version));
2093efecf7aSJan Kiszka memset(&ctr->profile, 0, sizeof(ctr->profile));
2103efecf7aSJan Kiszka memset(ctr->serial, 0, sizeof(ctr->serial));
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
213b003f4e1SJan Kiszka ap = __get_capi_appl_by_nr(applid);
21488c896efSJan Kiszka if (ap)
2153efecf7aSJan Kiszka capi_ctr_put(ctr);
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds }
2183efecf7aSJan Kiszka
notify_down(u32 contr)2193efecf7aSJan Kiszka static void notify_down(u32 contr)
2203efecf7aSJan Kiszka {
2213efecf7aSJan Kiszka struct capi_ctr *ctr;
2223efecf7aSJan Kiszka
2230ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
2240ca3a017SJan Kiszka
2253efecf7aSJan Kiszka if (showcapimsgs & 1)
2263efecf7aSJan Kiszka printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
2273efecf7aSJan Kiszka
2283efecf7aSJan Kiszka ctr = get_capi_ctr_by_nr(contr);
2293efecf7aSJan Kiszka if (ctr)
2300ca3a017SJan Kiszka ctr_down(ctr, CAPI_CTR_DETECTED);
2313efecf7aSJan Kiszka else
2323efecf7aSJan Kiszka printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
2330ca3a017SJan Kiszka
2340ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
2353efecf7aSJan Kiszka }
2361da177e4SLinus Torvalds
do_notify_work(struct work_struct * work)237ef69bb2eSJan Kiszka static void do_notify_work(struct work_struct *work)
238ef69bb2eSJan Kiszka {
239ef69bb2eSJan Kiszka struct capictr_event *event =
240ef69bb2eSJan Kiszka container_of(work, struct capictr_event, work);
241ef69bb2eSJan Kiszka
242f59aba2fSArnd Bergmann switch (event->type) {
243f59aba2fSArnd Bergmann case CAPICTR_UP:
244f59aba2fSArnd Bergmann notify_up(event->controller);
245f59aba2fSArnd Bergmann break;
246f59aba2fSArnd Bergmann case CAPICTR_DOWN:
247f59aba2fSArnd Bergmann notify_down(event->controller);
248f59aba2fSArnd Bergmann break;
249f59aba2fSArnd Bergmann }
250f59aba2fSArnd Bergmann
251ef69bb2eSJan Kiszka kfree(event);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds
notify_push(unsigned int event_type,u32 controller)254ef69bb2eSJan Kiszka static int notify_push(unsigned int event_type, u32 controller)
2551da177e4SLinus Torvalds {
256ef69bb2eSJan Kiszka struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC);
2571da177e4SLinus Torvalds
258ef69bb2eSJan Kiszka if (!event)
2591da177e4SLinus Torvalds return -ENOMEM;
2601da177e4SLinus Torvalds
261ef69bb2eSJan Kiszka INIT_WORK(&event->work, do_notify_work);
262ef69bb2eSJan Kiszka event->type = event_type;
263ef69bb2eSJan Kiszka event->controller = controller;
2641da177e4SLinus Torvalds
265158fa677STejun Heo queue_work(kcapi_wq, &event->work);
2661da177e4SLinus Torvalds return 0;
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds
2691da177e4SLinus Torvalds /* -------- Receiver ------------------------------------------ */
2701da177e4SLinus Torvalds
recv_handler(struct work_struct * work)271c4028958SDavid Howells static void recv_handler(struct work_struct *work)
2721da177e4SLinus Torvalds {
2731da177e4SLinus Torvalds struct sk_buff *skb;
274c4028958SDavid Howells struct capi20_appl *ap =
275c4028958SDavid Howells container_of(work, struct capi20_appl, recv_work);
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds if ((!ap) || (ap->release_in_progress))
2781da177e4SLinus Torvalds return;
2791da177e4SLinus Torvalds
28067837f23SMatthias Kaehlcke mutex_lock(&ap->recv_mtx);
2811da177e4SLinus Torvalds while ((skb = skb_dequeue(&ap->recv_queue))) {
2821da177e4SLinus Torvalds if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
2831da177e4SLinus Torvalds ap->nrecvdatapkt++;
2841da177e4SLinus Torvalds else
2851da177e4SLinus Torvalds ap->nrecvctlpkt++;
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds ap->recv_message(ap, skb);
2881da177e4SLinus Torvalds }
28967837f23SMatthias Kaehlcke mutex_unlock(&ap->recv_mtx);
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds
292554f200eSTilman Schmidt /**
293554f200eSTilman Schmidt * capi_ctr_handle_message() - handle incoming CAPI message
29452253031SJan Kiszka * @ctr: controller descriptor structure.
295554f200eSTilman Schmidt * @appl: application ID.
296554f200eSTilman Schmidt * @skb: message.
297554f200eSTilman Schmidt *
298554f200eSTilman Schmidt * Called by hardware driver to pass a CAPI message to the application.
299554f200eSTilman Schmidt */
300554f200eSTilman Schmidt
capi_ctr_handle_message(struct capi_ctr * ctr,u16 appl,struct sk_buff * skb)30152253031SJan Kiszka void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
30252253031SJan Kiszka struct sk_buff *skb)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds struct capi20_appl *ap;
3051da177e4SLinus Torvalds int showctl = 0;
3061da177e4SLinus Torvalds u8 cmd, subcmd;
30717f0cd2fSKarsten Keil _cdebbuf *cdb;
3081da177e4SLinus Torvalds
30952253031SJan Kiszka if (ctr->state != CAPI_CTR_RUNNING) {
31017f0cd2fSKarsten Keil cdb = capi_message2str(skb->data);
31117f0cd2fSKarsten Keil if (cdb) {
31217f0cd2fSKarsten Keil printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
31352253031SJan Kiszka ctr->cnr, cdb->buf);
31417f0cd2fSKarsten Keil cdebbuf_free(cdb);
31517f0cd2fSKarsten Keil } else
31617f0cd2fSKarsten Keil printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
31752253031SJan Kiszka ctr->cnr);
3181da177e4SLinus Torvalds goto error;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds
3211da177e4SLinus Torvalds cmd = CAPIMSG_COMMAND(skb->data);
3221da177e4SLinus Torvalds subcmd = CAPIMSG_SUBCOMMAND(skb->data);
3231da177e4SLinus Torvalds if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
32452253031SJan Kiszka ctr->nrecvdatapkt++;
32552253031SJan Kiszka if (ctr->traceflag > 2)
32652253031SJan Kiszka showctl |= 2;
3271da177e4SLinus Torvalds } else {
32852253031SJan Kiszka ctr->nrecvctlpkt++;
32952253031SJan Kiszka if (ctr->traceflag)
33052253031SJan Kiszka showctl |= 2;
3311da177e4SLinus Torvalds }
33252253031SJan Kiszka showctl |= (ctr->traceflag & 1);
3331da177e4SLinus Torvalds if (showctl & 2) {
3341da177e4SLinus Torvalds if (showctl & 1) {
33517f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
33652253031SJan Kiszka ctr->cnr, CAPIMSG_APPID(skb->data),
3371da177e4SLinus Torvalds capi_cmd2str(cmd, subcmd),
3381da177e4SLinus Torvalds CAPIMSG_LEN(skb->data));
3391da177e4SLinus Torvalds } else {
34017f0cd2fSKarsten Keil cdb = capi_message2str(skb->data);
34117f0cd2fSKarsten Keil if (cdb) {
34217f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
34352253031SJan Kiszka ctr->cnr, cdb->buf);
34417f0cd2fSKarsten Keil cdebbuf_free(cdb);
34517f0cd2fSKarsten Keil } else
34617f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
34752253031SJan Kiszka ctr->cnr, CAPIMSG_APPID(skb->data),
34817f0cd2fSKarsten Keil capi_cmd2str(cmd, subcmd),
34917f0cd2fSKarsten Keil CAPIMSG_LEN(skb->data));
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds
35488c896efSJan Kiszka rcu_read_lock();
3551da177e4SLinus Torvalds ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
35688c896efSJan Kiszka if (!ap) {
35788c896efSJan Kiszka rcu_read_unlock();
35817f0cd2fSKarsten Keil cdb = capi_message2str(skb->data);
35917f0cd2fSKarsten Keil if (cdb) {
3601da177e4SLinus Torvalds printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
36117f0cd2fSKarsten Keil CAPIMSG_APPID(skb->data), cdb->buf);
36217f0cd2fSKarsten Keil cdebbuf_free(cdb);
36317f0cd2fSKarsten Keil } else
36417f0cd2fSKarsten Keil printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
36517f0cd2fSKarsten Keil CAPIMSG_APPID(skb->data),
36617f0cd2fSKarsten Keil capi_cmd2str(cmd, subcmd));
3671da177e4SLinus Torvalds goto error;
3681da177e4SLinus Torvalds }
3691da177e4SLinus Torvalds skb_queue_tail(&ap->recv_queue, skb);
370158fa677STejun Heo queue_work(kcapi_wq, &ap->recv_work);
37188c896efSJan Kiszka rcu_read_unlock();
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds return;
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds error:
3761da177e4SLinus Torvalds kfree_skb(skb);
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds
3791da177e4SLinus Torvalds EXPORT_SYMBOL(capi_ctr_handle_message);
3801da177e4SLinus Torvalds
381554f200eSTilman Schmidt /**
382554f200eSTilman Schmidt * capi_ctr_ready() - signal CAPI controller ready
38352253031SJan Kiszka * @ctr: controller descriptor structure.
384554f200eSTilman Schmidt *
385554f200eSTilman Schmidt * Called by hardware driver to signal that the controller is up and running.
386554f200eSTilman Schmidt */
387554f200eSTilman Schmidt
capi_ctr_ready(struct capi_ctr * ctr)38852253031SJan Kiszka void capi_ctr_ready(struct capi_ctr *ctr)
3891da177e4SLinus Torvalds {
39052253031SJan Kiszka printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
39152253031SJan Kiszka ctr->cnr, ctr->name);
3921da177e4SLinus Torvalds
393ef69bb2eSJan Kiszka notify_push(CAPICTR_UP, ctr->cnr);
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds EXPORT_SYMBOL(capi_ctr_ready);
3971da177e4SLinus Torvalds
398554f200eSTilman Schmidt /**
3994e329972STilman Schmidt * capi_ctr_down() - signal CAPI controller not ready
40052253031SJan Kiszka * @ctr: controller descriptor structure.
401554f200eSTilman Schmidt *
402554f200eSTilman Schmidt * Called by hardware driver to signal that the controller is down and
403554f200eSTilman Schmidt * unavailable for use.
404554f200eSTilman Schmidt */
405554f200eSTilman Schmidt
capi_ctr_down(struct capi_ctr * ctr)40652253031SJan Kiszka void capi_ctr_down(struct capi_ctr *ctr)
4071da177e4SLinus Torvalds {
40852253031SJan Kiszka printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
4091da177e4SLinus Torvalds
410ef69bb2eSJan Kiszka notify_push(CAPICTR_DOWN, ctr->cnr);
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds
4134e329972STilman Schmidt EXPORT_SYMBOL(capi_ctr_down);
4141da177e4SLinus Torvalds
4151da177e4SLinus Torvalds /* ------------------------------------------------------------- */
4161da177e4SLinus Torvalds
417554f200eSTilman Schmidt /**
418554f200eSTilman Schmidt * attach_capi_ctr() - register CAPI controller
41952253031SJan Kiszka * @ctr: controller descriptor structure.
420554f200eSTilman Schmidt *
421554f200eSTilman Schmidt * Called by hardware driver to register a controller with the CAPI subsystem.
422554f200eSTilman Schmidt * Return value: 0 on success, error code < 0 on error
423554f200eSTilman Schmidt */
424554f200eSTilman Schmidt
attach_capi_ctr(struct capi_ctr * ctr)42552253031SJan Kiszka int attach_capi_ctr(struct capi_ctr *ctr)
4261da177e4SLinus Torvalds {
4271da177e4SLinus Torvalds int i;
4281da177e4SLinus Torvalds
4290ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds for (i = 0; i < CAPI_MAXCONTR; i++) {
43252253031SJan Kiszka if (!capi_controller[i])
4331da177e4SLinus Torvalds break;
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds if (i == CAPI_MAXCONTR) {
4360ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
4371da177e4SLinus Torvalds printk(KERN_ERR "kcapi: out of controller slots\n");
4381da177e4SLinus Torvalds return -EBUSY;
4391da177e4SLinus Torvalds }
44052253031SJan Kiszka capi_controller[i] = ctr;
4411da177e4SLinus Torvalds
44252253031SJan Kiszka ctr->nrecvctlpkt = 0;
44352253031SJan Kiszka ctr->nrecvdatapkt = 0;
44452253031SJan Kiszka ctr->nsentctlpkt = 0;
44552253031SJan Kiszka ctr->nsentdatapkt = 0;
44652253031SJan Kiszka ctr->cnr = i + 1;
44752253031SJan Kiszka ctr->state = CAPI_CTR_DETECTED;
44852253031SJan Kiszka ctr->blocked = 0;
44952253031SJan Kiszka ctr->traceflag = showcapimsgs;
4501da177e4SLinus Torvalds
45152253031SJan Kiszka sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
4522cd1f0ddSChristoph Hellwig ctr->procent = proc_create_single_data(ctr->procfn, 0, NULL,
4532cd1f0ddSChristoph Hellwig ctr->proc_show, ctr);
4541da177e4SLinus Torvalds
45552253031SJan Kiszka ncontrollers++;
4560ca3a017SJan Kiszka
4570ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
4580ca3a017SJan Kiszka
45952253031SJan Kiszka printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
46052253031SJan Kiszka ctr->cnr, ctr->name);
4611da177e4SLinus Torvalds return 0;
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds EXPORT_SYMBOL(attach_capi_ctr);
4651da177e4SLinus Torvalds
466554f200eSTilman Schmidt /**
467554f200eSTilman Schmidt * detach_capi_ctr() - unregister CAPI controller
46852253031SJan Kiszka * @ctr: controller descriptor structure.
469554f200eSTilman Schmidt *
470554f200eSTilman Schmidt * Called by hardware driver to remove the registration of a controller
471554f200eSTilman Schmidt * with the CAPI subsystem.
472554f200eSTilman Schmidt * Return value: 0 on success, error code < 0 on error
473554f200eSTilman Schmidt */
474554f200eSTilman Schmidt
detach_capi_ctr(struct capi_ctr * ctr)47552253031SJan Kiszka int detach_capi_ctr(struct capi_ctr *ctr)
4761da177e4SLinus Torvalds {
4770ca3a017SJan Kiszka int err = 0;
4781da177e4SLinus Torvalds
4790ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
4801da177e4SLinus Torvalds
4810ca3a017SJan Kiszka ctr_down(ctr, CAPI_CTR_DETACHED);
4820ca3a017SJan Kiszka
4831f3e2e97SXiaolong Huang if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) {
4841f3e2e97SXiaolong Huang err = -EINVAL;
4851f3e2e97SXiaolong Huang goto unlock_out;
4861f3e2e97SXiaolong Huang }
4871f3e2e97SXiaolong Huang
4880ca3a017SJan Kiszka if (capi_controller[ctr->cnr - 1] != ctr) {
4890ca3a017SJan Kiszka err = -EINVAL;
4900ca3a017SJan Kiszka goto unlock_out;
4911da177e4SLinus Torvalds }
49252253031SJan Kiszka capi_controller[ctr->cnr - 1] = NULL;
4930ca3a017SJan Kiszka ncontrollers--;
4940ca3a017SJan Kiszka
4950ca3a017SJan Kiszka if (ctr->procent)
4960ca3a017SJan Kiszka remove_proc_entry(ctr->procfn, NULL);
4970ca3a017SJan Kiszka
49852253031SJan Kiszka printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
49952253031SJan Kiszka ctr->cnr, ctr->name);
5001da177e4SLinus Torvalds
5010ca3a017SJan Kiszka unlock_out:
5020ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
5030ca3a017SJan Kiszka
5040ca3a017SJan Kiszka return err;
5051da177e4SLinus Torvalds }
5061da177e4SLinus Torvalds
5071da177e4SLinus Torvalds EXPORT_SYMBOL(detach_capi_ctr);
5081da177e4SLinus Torvalds
5091da177e4SLinus Torvalds /* ------------------------------------------------------------- */
5101da177e4SLinus Torvalds /* -------- CAPI2.0 Interface ---------------------------------- */
5111da177e4SLinus Torvalds /* ------------------------------------------------------------- */
5121da177e4SLinus Torvalds
513554f200eSTilman Schmidt /**
514554f200eSTilman Schmidt * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
515554f200eSTilman Schmidt *
516554f200eSTilman Schmidt * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
517554f200eSTilman Schmidt * is ready for use, CAPI_REGNOTINSTALLED otherwise)
518554f200eSTilman Schmidt */
519554f200eSTilman Schmidt
capi20_isinstalled(void)5201da177e4SLinus Torvalds u16 capi20_isinstalled(void)
5211da177e4SLinus Torvalds {
5220ca3a017SJan Kiszka u16 ret = CAPI_REGNOTINSTALLED;
5231da177e4SLinus Torvalds int i;
5240ca3a017SJan Kiszka
5250ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
5260ca3a017SJan Kiszka
5270ca3a017SJan Kiszka for (i = 0; i < CAPI_MAXCONTR; i++)
52852253031SJan Kiszka if (capi_controller[i] &&
5290ca3a017SJan Kiszka capi_controller[i]->state == CAPI_CTR_RUNNING) {
5300ca3a017SJan Kiszka ret = CAPI_NOERROR;
5310ca3a017SJan Kiszka break;
5321da177e4SLinus Torvalds }
5330ca3a017SJan Kiszka
5340ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
5350ca3a017SJan Kiszka
5360ca3a017SJan Kiszka return ret;
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds
539554f200eSTilman Schmidt /**
540554f200eSTilman Schmidt * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
541554f200eSTilman Schmidt * @ap: CAPI application descriptor structure.
542554f200eSTilman Schmidt *
543554f200eSTilman Schmidt * Register an application's presence with CAPI.
544554f200eSTilman Schmidt * A unique application ID is assigned and stored in @ap->applid.
545554f200eSTilman Schmidt * After this function returns successfully, the message receive
546554f200eSTilman Schmidt * callback function @ap->recv_message() may be called at any time
547554f200eSTilman Schmidt * until capi20_release() has been called for the same @ap.
548554f200eSTilman Schmidt * Return value: CAPI result code
549554f200eSTilman Schmidt */
550554f200eSTilman Schmidt
capi20_register(struct capi20_appl * ap)5511da177e4SLinus Torvalds u16 capi20_register(struct capi20_appl *ap)
5521da177e4SLinus Torvalds {
5531da177e4SLinus Torvalds int i;
5541da177e4SLinus Torvalds u16 applid;
5551da177e4SLinus Torvalds
5561da177e4SLinus Torvalds DBG("");
5571da177e4SLinus Torvalds
5581da177e4SLinus Torvalds if (ap->rparam.datablklen < 128)
5591da177e4SLinus Torvalds return CAPI_LOGBLKSIZETOSMALL;
5601da177e4SLinus Torvalds
5611da177e4SLinus Torvalds ap->nrecvctlpkt = 0;
5621da177e4SLinus Torvalds ap->nrecvdatapkt = 0;
5631da177e4SLinus Torvalds ap->nsentctlpkt = 0;
5641da177e4SLinus Torvalds ap->nsentdatapkt = 0;
56567837f23SMatthias Kaehlcke mutex_init(&ap->recv_mtx);
5661da177e4SLinus Torvalds skb_queue_head_init(&ap->recv_queue);
567c4028958SDavid Howells INIT_WORK(&ap->recv_work, recv_handler);
5681da177e4SLinus Torvalds ap->release_in_progress = 0;
5691da177e4SLinus Torvalds
5700ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
5710ca3a017SJan Kiszka
57288c896efSJan Kiszka for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
57388c896efSJan Kiszka if (capi_applications[applid - 1] == NULL)
57488c896efSJan Kiszka break;
57588c896efSJan Kiszka }
57688c896efSJan Kiszka if (applid > CAPI_MAXAPPL) {
57788c896efSJan Kiszka mutex_unlock(&capi_controller_lock);
57888c896efSJan Kiszka return CAPI_TOOMANYAPPLS;
57988c896efSJan Kiszka }
58088c896efSJan Kiszka
58188c896efSJan Kiszka ap->applid = applid;
58288c896efSJan Kiszka capi_applications[applid - 1] = ap;
58388c896efSJan Kiszka
5841da177e4SLinus Torvalds for (i = 0; i < CAPI_MAXCONTR; i++) {
58552253031SJan Kiszka if (!capi_controller[i] ||
58652253031SJan Kiszka capi_controller[i]->state != CAPI_CTR_RUNNING)
5871da177e4SLinus Torvalds continue;
58852253031SJan Kiszka register_appl(capi_controller[i], applid, &ap->rparam);
5891da177e4SLinus Torvalds }
5900ca3a017SJan Kiszka
5910ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
5921da177e4SLinus Torvalds
5931da177e4SLinus Torvalds if (showcapimsgs & 1) {
5941da177e4SLinus Torvalds printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
5951da177e4SLinus Torvalds }
5961da177e4SLinus Torvalds
5971da177e4SLinus Torvalds return CAPI_NOERROR;
5981da177e4SLinus Torvalds }
5991da177e4SLinus Torvalds
600554f200eSTilman Schmidt /**
601554f200eSTilman Schmidt * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
602554f200eSTilman Schmidt * @ap: CAPI application descriptor structure.
603554f200eSTilman Schmidt *
604554f200eSTilman Schmidt * Terminate an application's registration with CAPI.
605554f200eSTilman Schmidt * After this function returns successfully, the message receive
606554f200eSTilman Schmidt * callback function @ap->recv_message() will no longer be called.
607554f200eSTilman Schmidt * Return value: CAPI result code
608554f200eSTilman Schmidt */
609554f200eSTilman Schmidt
capi20_release(struct capi20_appl * ap)6101da177e4SLinus Torvalds u16 capi20_release(struct capi20_appl *ap)
6111da177e4SLinus Torvalds {
6121da177e4SLinus Torvalds int i;
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds DBG("applid %#x", ap->applid);
6151da177e4SLinus Torvalds
61688c896efSJan Kiszka mutex_lock(&capi_controller_lock);
61788c896efSJan Kiszka
6181da177e4SLinus Torvalds ap->release_in_progress = 1;
6191da177e4SLinus Torvalds capi_applications[ap->applid - 1] = NULL;
6201da177e4SLinus Torvalds
62188c896efSJan Kiszka synchronize_rcu();
6220ca3a017SJan Kiszka
6231da177e4SLinus Torvalds for (i = 0; i < CAPI_MAXCONTR; i++) {
62452253031SJan Kiszka if (!capi_controller[i] ||
62552253031SJan Kiszka capi_controller[i]->state != CAPI_CTR_RUNNING)
6261da177e4SLinus Torvalds continue;
62752253031SJan Kiszka release_appl(capi_controller[i], ap->applid);
6281da177e4SLinus Torvalds }
6290ca3a017SJan Kiszka
6300ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
6311da177e4SLinus Torvalds
632158fa677STejun Heo flush_workqueue(kcapi_wq);
6331da177e4SLinus Torvalds skb_queue_purge(&ap->recv_queue);
6341da177e4SLinus Torvalds
6351da177e4SLinus Torvalds if (showcapimsgs & 1) {
6361da177e4SLinus Torvalds printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
6371da177e4SLinus Torvalds }
6381da177e4SLinus Torvalds
6391da177e4SLinus Torvalds return CAPI_NOERROR;
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds
642554f200eSTilman Schmidt /**
643554f200eSTilman Schmidt * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
644554f200eSTilman Schmidt * @ap: CAPI application descriptor structure.
645554f200eSTilman Schmidt * @skb: CAPI message.
646554f200eSTilman Schmidt *
647554f200eSTilman Schmidt * Transfer a single message to CAPI.
648554f200eSTilman Schmidt * Return value: CAPI result code
649554f200eSTilman Schmidt */
650554f200eSTilman Schmidt
capi20_put_message(struct capi20_appl * ap,struct sk_buff * skb)6511da177e4SLinus Torvalds u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
6521da177e4SLinus Torvalds {
65352253031SJan Kiszka struct capi_ctr *ctr;
6541da177e4SLinus Torvalds int showctl = 0;
6551da177e4SLinus Torvalds u8 cmd, subcmd;
6561da177e4SLinus Torvalds
6571da177e4SLinus Torvalds DBG("applid %#x", ap->applid);
6581da177e4SLinus Torvalds
65952253031SJan Kiszka if (ncontrollers == 0)
6601da177e4SLinus Torvalds return CAPI_REGNOTINSTALLED;
6611da177e4SLinus Torvalds if ((ap->applid == 0) || ap->release_in_progress)
6621da177e4SLinus Torvalds return CAPI_ILLAPPNR;
6631da177e4SLinus Torvalds if (skb->len < 12
6641da177e4SLinus Torvalds || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
6651da177e4SLinus Torvalds || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
6661da177e4SLinus Torvalds return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
6670ca3a017SJan Kiszka
6680ca3a017SJan Kiszka /*
6690ca3a017SJan Kiszka * The controller reference is protected by the existence of the
6700ca3a017SJan Kiszka * application passed to us. We assume that the caller properly
6710ca3a017SJan Kiszka * synchronizes this service with capi20_release.
6720ca3a017SJan Kiszka */
67352253031SJan Kiszka ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
67452253031SJan Kiszka if (!ctr || ctr->state != CAPI_CTR_RUNNING)
6751da177e4SLinus Torvalds return CAPI_REGNOTINSTALLED;
67652253031SJan Kiszka if (ctr->blocked)
6771da177e4SLinus Torvalds return CAPI_SENDQUEUEFULL;
6781da177e4SLinus Torvalds
6791da177e4SLinus Torvalds cmd = CAPIMSG_COMMAND(skb->data);
6801da177e4SLinus Torvalds subcmd = CAPIMSG_SUBCOMMAND(skb->data);
6811da177e4SLinus Torvalds
6821da177e4SLinus Torvalds if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
68352253031SJan Kiszka ctr->nsentdatapkt++;
6841da177e4SLinus Torvalds ap->nsentdatapkt++;
68552253031SJan Kiszka if (ctr->traceflag > 2)
68652253031SJan Kiszka showctl |= 2;
6871da177e4SLinus Torvalds } else {
68852253031SJan Kiszka ctr->nsentctlpkt++;
6891da177e4SLinus Torvalds ap->nsentctlpkt++;
69052253031SJan Kiszka if (ctr->traceflag)
69152253031SJan Kiszka showctl |= 2;
6921da177e4SLinus Torvalds }
69352253031SJan Kiszka showctl |= (ctr->traceflag & 1);
6941da177e4SLinus Torvalds if (showctl & 2) {
6951da177e4SLinus Torvalds if (showctl & 1) {
69617f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
6971da177e4SLinus Torvalds CAPIMSG_CONTROLLER(skb->data),
6981da177e4SLinus Torvalds CAPIMSG_APPID(skb->data),
6991da177e4SLinus Torvalds capi_cmd2str(cmd, subcmd),
7001da177e4SLinus Torvalds CAPIMSG_LEN(skb->data));
7011da177e4SLinus Torvalds } else {
70217f0cd2fSKarsten Keil _cdebbuf *cdb = capi_message2str(skb->data);
70317f0cd2fSKarsten Keil if (cdb) {
70417f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
7051da177e4SLinus Torvalds CAPIMSG_CONTROLLER(skb->data),
70617f0cd2fSKarsten Keil cdb->buf);
70717f0cd2fSKarsten Keil cdebbuf_free(cdb);
70817f0cd2fSKarsten Keil } else
70917f0cd2fSKarsten Keil printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
71017f0cd2fSKarsten Keil CAPIMSG_CONTROLLER(skb->data),
71117f0cd2fSKarsten Keil CAPIMSG_APPID(skb->data),
71217f0cd2fSKarsten Keil capi_cmd2str(cmd, subcmd),
71317f0cd2fSKarsten Keil CAPIMSG_LEN(skb->data));
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds }
71652253031SJan Kiszka return ctr->send_message(ctr, skb);
7171da177e4SLinus Torvalds }
7181da177e4SLinus Torvalds
719554f200eSTilman Schmidt /**
720554f200eSTilman Schmidt * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
721554f200eSTilman Schmidt * @contr: controller number.
722554f200eSTilman Schmidt * @buf: result buffer (64 bytes).
723554f200eSTilman Schmidt *
724554f200eSTilman Schmidt * Retrieve information about the manufacturer of the specified ISDN controller
725554f200eSTilman Schmidt * or (for @contr == 0) the driver itself.
726554f200eSTilman Schmidt * Return value: CAPI result code
727554f200eSTilman Schmidt */
728554f200eSTilman Schmidt
capi20_get_manufacturer(u32 contr,u8 buf[CAPI_MANUFACTURER_LEN])7295ee7d4c7SArnd Bergmann u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
7301da177e4SLinus Torvalds {
73152253031SJan Kiszka struct capi_ctr *ctr;
7320ca3a017SJan Kiszka u16 ret;
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds if (contr == 0) {
735d63967e4SEric Dumazet strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
7361da177e4SLinus Torvalds return CAPI_NOERROR;
7371da177e4SLinus Torvalds }
7380ca3a017SJan Kiszka
7390ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
7400ca3a017SJan Kiszka
74152253031SJan Kiszka ctr = get_capi_ctr_by_nr(contr);
7420ca3a017SJan Kiszka if (ctr && ctr->state == CAPI_CTR_RUNNING) {
743d63967e4SEric Dumazet strncpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
7440ca3a017SJan Kiszka ret = CAPI_NOERROR;
7450ca3a017SJan Kiszka } else
7460ca3a017SJan Kiszka ret = CAPI_REGNOTINSTALLED;
7470ca3a017SJan Kiszka
7480ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
7490ca3a017SJan Kiszka return ret;
7501da177e4SLinus Torvalds }
7511da177e4SLinus Torvalds
752554f200eSTilman Schmidt /**
753554f200eSTilman Schmidt * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
754554f200eSTilman Schmidt * @contr: controller number.
755554f200eSTilman Schmidt * @verp: result structure.
756554f200eSTilman Schmidt *
757554f200eSTilman Schmidt * Retrieve version information for the specified ISDN controller
758554f200eSTilman Schmidt * or (for @contr == 0) the driver itself.
759554f200eSTilman Schmidt * Return value: CAPI result code
760554f200eSTilman Schmidt */
761554f200eSTilman Schmidt
capi20_get_version(u32 contr,struct capi_version * verp)7621da177e4SLinus Torvalds u16 capi20_get_version(u32 contr, struct capi_version *verp)
7631da177e4SLinus Torvalds {
76452253031SJan Kiszka struct capi_ctr *ctr;
7650ca3a017SJan Kiszka u16 ret;
7661da177e4SLinus Torvalds
7671da177e4SLinus Torvalds if (contr == 0) {
7681da177e4SLinus Torvalds *verp = driver_version;
7691da177e4SLinus Torvalds return CAPI_NOERROR;
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds
7720ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
7730ca3a017SJan Kiszka
7740ca3a017SJan Kiszka ctr = get_capi_ctr_by_nr(contr);
7750ca3a017SJan Kiszka if (ctr && ctr->state == CAPI_CTR_RUNNING) {
77652253031SJan Kiszka memcpy(verp, &ctr->version, sizeof(capi_version));
7770ca3a017SJan Kiszka ret = CAPI_NOERROR;
7780ca3a017SJan Kiszka } else
7790ca3a017SJan Kiszka ret = CAPI_REGNOTINSTALLED;
7800ca3a017SJan Kiszka
7810ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
7820ca3a017SJan Kiszka return ret;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds
785554f200eSTilman Schmidt /**
786554f200eSTilman Schmidt * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
787554f200eSTilman Schmidt * @contr: controller number.
788554f200eSTilman Schmidt * @serial: result buffer (8 bytes).
789554f200eSTilman Schmidt *
790554f200eSTilman Schmidt * Retrieve the serial number of the specified ISDN controller
791554f200eSTilman Schmidt * or (for @contr == 0) the driver itself.
792554f200eSTilman Schmidt * Return value: CAPI result code
793554f200eSTilman Schmidt */
794554f200eSTilman Schmidt
capi20_get_serial(u32 contr,u8 serial[CAPI_SERIAL_LEN])7955ee7d4c7SArnd Bergmann u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN])
7961da177e4SLinus Torvalds {
79752253031SJan Kiszka struct capi_ctr *ctr;
7980ca3a017SJan Kiszka u16 ret;
7991da177e4SLinus Torvalds
8001da177e4SLinus Torvalds if (contr == 0) {
801*cdb27b7bSWolfram Sang strscpy(serial, driver_serial, CAPI_SERIAL_LEN);
8021da177e4SLinus Torvalds return CAPI_NOERROR;
8031da177e4SLinus Torvalds }
8041da177e4SLinus Torvalds
8050ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
8060ca3a017SJan Kiszka
8070ca3a017SJan Kiszka ctr = get_capi_ctr_by_nr(contr);
8080ca3a017SJan Kiszka if (ctr && ctr->state == CAPI_CTR_RUNNING) {
809*cdb27b7bSWolfram Sang strscpy(serial, ctr->serial, CAPI_SERIAL_LEN);
8100ca3a017SJan Kiszka ret = CAPI_NOERROR;
8110ca3a017SJan Kiszka } else
8120ca3a017SJan Kiszka ret = CAPI_REGNOTINSTALLED;
8130ca3a017SJan Kiszka
8140ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
8150ca3a017SJan Kiszka return ret;
8161da177e4SLinus Torvalds }
8171da177e4SLinus Torvalds
818554f200eSTilman Schmidt /**
819554f200eSTilman Schmidt * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
820554f200eSTilman Schmidt * @contr: controller number.
821554f200eSTilman Schmidt * @profp: result structure.
822554f200eSTilman Schmidt *
823554f200eSTilman Schmidt * Retrieve capability information for the specified ISDN controller
824554f200eSTilman Schmidt * or (for @contr == 0) the number of installed controllers.
825554f200eSTilman Schmidt * Return value: CAPI result code
826554f200eSTilman Schmidt */
827554f200eSTilman Schmidt
capi20_get_profile(u32 contr,struct capi_profile * profp)8281da177e4SLinus Torvalds u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
8291da177e4SLinus Torvalds {
83052253031SJan Kiszka struct capi_ctr *ctr;
8310ca3a017SJan Kiszka u16 ret;
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds if (contr == 0) {
83452253031SJan Kiszka profp->ncontroller = ncontrollers;
8351da177e4SLinus Torvalds return CAPI_NOERROR;
8361da177e4SLinus Torvalds }
8371da177e4SLinus Torvalds
8380ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
8390ca3a017SJan Kiszka
8400ca3a017SJan Kiszka ctr = get_capi_ctr_by_nr(contr);
8410ca3a017SJan Kiszka if (ctr && ctr->state == CAPI_CTR_RUNNING) {
84252253031SJan Kiszka memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
8430ca3a017SJan Kiszka ret = CAPI_NOERROR;
8440ca3a017SJan Kiszka } else
8450ca3a017SJan Kiszka ret = CAPI_REGNOTINSTALLED;
8460ca3a017SJan Kiszka
8470ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
8480ca3a017SJan Kiszka return ret;
8491da177e4SLinus Torvalds }
8501da177e4SLinus Torvalds
851554f200eSTilman Schmidt /**
852554f200eSTilman Schmidt * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
853554f200eSTilman Schmidt * @cmd: command.
854554f200eSTilman Schmidt * @data: parameter.
855554f200eSTilman Schmidt *
856554f200eSTilman Schmidt * Perform manufacturer specific command.
857554f200eSTilman Schmidt * Return value: CAPI result code
858554f200eSTilman Schmidt */
859554f200eSTilman Schmidt
capi20_manufacturer(unsigned long cmd,void __user * data)8609ea8aa8dSTilman Schmidt int capi20_manufacturer(unsigned long cmd, void __user *data)
8611da177e4SLinus Torvalds {
86252253031SJan Kiszka struct capi_ctr *ctr;
8630ca3a017SJan Kiszka int retval;
8641da177e4SLinus Torvalds
8651da177e4SLinus Torvalds switch (cmd) {
8661da177e4SLinus Torvalds case KCAPI_CMD_TRACE:
8671da177e4SLinus Torvalds {
8681da177e4SLinus Torvalds kcapi_flagdef fdef;
8691da177e4SLinus Torvalds
8701da177e4SLinus Torvalds if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
8711da177e4SLinus Torvalds return -EFAULT;
8721da177e4SLinus Torvalds
8730ca3a017SJan Kiszka mutex_lock(&capi_controller_lock);
8741da177e4SLinus Torvalds
8750ca3a017SJan Kiszka ctr = get_capi_ctr_by_nr(fdef.contr);
8760ca3a017SJan Kiszka if (ctr) {
87752253031SJan Kiszka ctr->traceflag = fdef.flag;
87817f0cd2fSKarsten Keil printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
87952253031SJan Kiszka ctr->cnr, ctr->traceflag);
8800ca3a017SJan Kiszka retval = 0;
8810ca3a017SJan Kiszka } else
8820ca3a017SJan Kiszka retval = -ESRCH;
8830ca3a017SJan Kiszka
8840ca3a017SJan Kiszka mutex_unlock(&capi_controller_lock);
8850ca3a017SJan Kiszka
8860ca3a017SJan Kiszka return retval;
8871da177e4SLinus Torvalds }
8881da177e4SLinus Torvalds
8891da177e4SLinus Torvalds default:
8909ea8aa8dSTilman Schmidt printk(KERN_ERR "kcapi: manufacturer command %lu unknown.\n",
8911da177e4SLinus Torvalds cmd);
8921da177e4SLinus Torvalds break;
8931da177e4SLinus Torvalds
8941da177e4SLinus Torvalds }
8951da177e4SLinus Torvalds return -EINVAL;
8961da177e4SLinus Torvalds }
8971da177e4SLinus Torvalds
8981da177e4SLinus Torvalds /* ------------------------------------------------------------- */
8991da177e4SLinus Torvalds /* -------- Init & Cleanup ------------------------------------- */
9001da177e4SLinus Torvalds /* ------------------------------------------------------------- */
9011da177e4SLinus Torvalds
9021da177e4SLinus Torvalds /*
9031da177e4SLinus Torvalds * init / exit functions
9041da177e4SLinus Torvalds */
9051da177e4SLinus Torvalds
kcapi_init(void)906f59aba2fSArnd Bergmann int __init kcapi_init(void)
9071da177e4SLinus Torvalds {
90888549d6bSJan Kiszka int err;
9091da177e4SLinus Torvalds
910158fa677STejun Heo kcapi_wq = alloc_workqueue("kcapi", 0, 0);
911158fa677STejun Heo if (!kcapi_wq)
912158fa677STejun Heo return -ENOMEM;
913158fa677STejun Heo
91488549d6bSJan Kiszka err = cdebug_init();
915158fa677STejun Heo if (err) {
916158fa677STejun Heo destroy_workqueue(kcapi_wq);
91788549d6bSJan Kiszka return err;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
920158fa677STejun Heo kcapi_proc_init();
921158fa677STejun Heo return 0;
922158fa677STejun Heo }
923158fa677STejun Heo
kcapi_exit(void)924f59aba2fSArnd Bergmann void kcapi_exit(void)
9251da177e4SLinus Torvalds {
9261da177e4SLinus Torvalds kcapi_proc_exit();
9271da177e4SLinus Torvalds
92817f0cd2fSKarsten Keil cdebug_exit();
929158fa677STejun Heo destroy_workqueue(kcapi_wq);
9301da177e4SLinus Torvalds }
931