Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2    CMTP implementation for Linux Bluetooth stack (BlueZ).
  3    Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
  4 
  5    This program is free software; you can redistribute it and/or modify
  6    it under the terms of the GNU General Public License version 2 as
  7    published by the Free Software Foundation;
  8 
  9    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 10    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 11    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 12    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
 13    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
 14    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17 
 18    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
 19    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
 20    SOFTWARE IS DISCLAIMED.
 21 */
 22 
 23 #include <linux/module.h>
 24 
 25 #include <linux/types.h>
 26 #include <linux/errno.h>
 27 #include <linux/kernel.h>
 28 #include <linux/sched.h>
 29 #include <linux/slab.h>
 30 #include <linux/poll.h>
 31 #include <linux/fcntl.h>
 32 #include <linux/skbuff.h>
 33 #include <linux/socket.h>
 34 #include <linux/ioctl.h>
 35 #include <linux/file.h>
 36 #include <linux/wait.h>
 37 #include <net/sock.h>
 38 
 39 #include <linux/isdn/capilli.h>
 40 #include <linux/isdn/capicmd.h>
 41 #include <linux/isdn/capiutil.h>
 42 
 43 #include "cmtp.h"
 44 
 45 #ifndef CONFIG_BT_CMTP_DEBUG
 46 #undef  BT_DBG
 47 #define BT_DBG(D...)
 48 #endif
 49 
 50 #define CAPI_INTEROPERABILITY           0x20
 51 
 52 #define CAPI_INTEROPERABILITY_REQ       CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
 53 #define CAPI_INTEROPERABILITY_CONF      CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
 54 #define CAPI_INTEROPERABILITY_IND       CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
 55 #define CAPI_INTEROPERABILITY_RESP      CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
 56 
 57 #define CAPI_INTEROPERABILITY_REQ_LEN   (CAPI_MSG_BASELEN + 2)
 58 #define CAPI_INTEROPERABILITY_CONF_LEN  (CAPI_MSG_BASELEN + 4)
 59 #define CAPI_INTEROPERABILITY_IND_LEN   (CAPI_MSG_BASELEN + 2)
 60 #define CAPI_INTEROPERABILITY_RESP_LEN  (CAPI_MSG_BASELEN + 2)
 61 
 62 #define CAPI_FUNCTION_REGISTER          0
 63 #define CAPI_FUNCTION_RELEASE           1
 64 #define CAPI_FUNCTION_GET_PROFILE       2
 65 #define CAPI_FUNCTION_GET_MANUFACTURER  3
 66 #define CAPI_FUNCTION_GET_VERSION       4
 67 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
 68 #define CAPI_FUNCTION_MANUFACTURER      6
 69 #define CAPI_FUNCTION_LOOPBACK          7
 70 
 71 
 72 #define CMTP_MSGNUM     1
 73 #define CMTP_APPLID     2
 74 #define CMTP_MAPPING    3
 75 
 76 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
 77 {
 78         struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
 79 
 80         BT_DBG("session %p application %p appl %d", session, app, appl);
 81 
 82         if (!app)
 83                 return NULL;
 84 
 85         app->state = BT_OPEN;
 86         app->appl = appl;
 87 
 88         list_add_tail(&app->list, &session->applications);
 89 
 90         return app;
 91 }
 92 
 93 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
 94 {
 95         BT_DBG("session %p application %p", session, app);
 96 
 97         if (app) {
 98                 list_del(&app->list);
 99                 kfree(app);
100         }
101 }
102 
103 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
104 {
105         struct cmtp_application *app;
106         struct list_head *p, *n;
107 
108         list_for_each_safe(p, n, &session->applications) {
109                 app = list_entry(p, struct cmtp_application, list);
110                 switch (pattern) {
111                 case CMTP_MSGNUM:
112                         if (app->msgnum == value)
113                                 return app;
114                         break;
115                 case CMTP_APPLID:
116                         if (app->appl == value)
117                                 return app;
118                         break;
119                 case CMTP_MAPPING:
120                         if (app->mapping == value)
121                                 return app;
122                         break;
123                 }
124         }
125 
126         return NULL;
127 }
128 
129 static int cmtp_msgnum_get(struct cmtp_session *session)
130 {
131         session->msgnum++;
132 
133         if ((session->msgnum & 0xff) > 200)
134                 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
135 
136         return session->msgnum;
137 }
138 
139 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
140 {
141         struct cmtp_scb *scb = (void *) skb->cb;
142 
143         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
144 
145         scb->id = -1;
146         scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
147 
148         skb_queue_tail(&session->transmit, skb);
149 
150         cmtp_schedule(session);
151 }
152 
153 static void cmtp_send_interopmsg(struct cmtp_session *session,
154                                         __u8 subcmd, __u16 appl, __u16 msgnum,
155                                         __u16 function, unsigned char *buf, int len)
156 {
157         struct sk_buff *skb;
158         unsigned char *s;
159 
160         BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
161 
162         if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
163                 BT_ERR("Can't allocate memory for interoperability packet");
164                 return;
165         }
166 
167         s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
168 
169         capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
170         capimsg_setu16(s, 2, appl);
171         capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
172         capimsg_setu8 (s, 5, subcmd);
173         capimsg_setu16(s, 6, msgnum);
174 
175         /* Interoperability selector (Bluetooth Device Management) */
176         capimsg_setu16(s, 8, 0x0001);
177 
178         capimsg_setu8 (s, 10, 3 + len);
179         capimsg_setu16(s, 11, function);
180         capimsg_setu8 (s, 13, len);
181 
182         if (len > 0)
183                 memcpy(s + 14, buf, len);
184 
185         cmtp_send_capimsg(session, skb);
186 }
187 
188 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
189 {
190         struct capi_ctr *ctrl = &session->ctrl;
191         struct cmtp_application *application;
192         __u16 appl, msgnum, func, info;
193         __u32 controller;
194 
195         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
196 
197         switch (CAPIMSG_SUBCOMMAND(skb->data)) {
198         case CAPI_CONF:
199                 if (skb->len < CAPI_MSG_BASELEN + 10)
200                         break;
201 
202                 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
203                 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
204 
205                 switch (func) {
206                 case CAPI_FUNCTION_REGISTER:
207                         msgnum = CAPIMSG_MSGID(skb->data);
208 
209                         application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
210                         if (application) {
211                                 application->state = BT_CONNECTED;
212                                 application->msgnum = 0;
213                                 application->mapping = CAPIMSG_APPID(skb->data);
214                                 wake_up_interruptible(&session->wait);
215                         }
216 
217                         break;
218 
219                 case CAPI_FUNCTION_RELEASE:
220                         appl = CAPIMSG_APPID(skb->data);
221 
222                         application = cmtp_application_get(session, CMTP_MAPPING, appl);
223                         if (application) {
224                                 application->state = BT_CLOSED;
225                                 application->msgnum = 0;
226                                 wake_up_interruptible(&session->wait);
227                         }
228 
229                         break;
230 
231                 case CAPI_FUNCTION_GET_PROFILE:
232                         if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
233                                 break;
234 
235                         controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
236                         msgnum = CAPIMSG_MSGID(skb->data);
237 
238                         if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
239                                 session->ncontroller = controller;
240                                 wake_up_interruptible(&session->wait);
241                                 break;
242                         }
243 
244                         if (!info && ctrl) {
245                                 memcpy(&ctrl->profile,
246                                         skb->data + CAPI_MSG_BASELEN + 11,
247                                         sizeof(capi_profile));
248                                 session->state = BT_CONNECTED;
249                                 capi_ctr_ready(ctrl);
250                         }
251 
252                         break;
253 
254                 case CAPI_FUNCTION_GET_MANUFACTURER:
255                         if (skb->len < CAPI_MSG_BASELEN + 15)
256                                 break;
257 
258                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
259 
260                         if (!info && ctrl) {
261                                 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
262                                                 skb->data[CAPI_MSG_BASELEN + 14]);
263 
264                                 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
265                                 strncpy(ctrl->manu,
266                                         skb->data + CAPI_MSG_BASELEN + 15, len);
267                         }
268 
269                         break;
270 
271                 case CAPI_FUNCTION_GET_VERSION:
272                         if (skb->len < CAPI_MSG_BASELEN + 32)
273                                 break;
274 
275                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
276 
277                         if (!info && ctrl) {
278                                 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
279                                 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
280                                 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
281                                 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
282                         }
283 
284                         break;
285 
286                 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
287                         if (skb->len < CAPI_MSG_BASELEN + 17)
288                                 break;
289 
290                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
291 
292                         if (!info && ctrl) {
293                                 int len = min_t(uint, CAPI_SERIAL_LEN,
294                                                 skb->data[CAPI_MSG_BASELEN + 16]);
295 
296                                 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
297                                 strncpy(ctrl->serial,
298                                         skb->data + CAPI_MSG_BASELEN + 17, len);
299                         }
300 
301                         break;
302                 }
303 
304                 break;
305 
306         case CAPI_IND:
307                 if (skb->len < CAPI_MSG_BASELEN + 6)
308                         break;
309 
310                 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
311 
312                 if (func == CAPI_FUNCTION_LOOPBACK) {
313                         int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
314                                                 skb->data[CAPI_MSG_BASELEN + 5]);
315                         appl = CAPIMSG_APPID(skb->data);
316                         msgnum = CAPIMSG_MSGID(skb->data);
317                         cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
318                                                 skb->data + CAPI_MSG_BASELEN + 6, len);
319                 }
320 
321                 break;
322         }
323 
324         kfree_skb(skb);
325 }
326 
327 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
328 {
329         struct capi_ctr *ctrl = &session->ctrl;
330         struct cmtp_application *application;
331         __u16 cmd, appl;
332         __u32 contr;
333 
334         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
335 
336         if (skb->len < CAPI_MSG_BASELEN)
337                 return;
338 
339         if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
340                 cmtp_recv_interopmsg(session, skb);
341                 return;
342         }
343 
344         if (session->flags & (1 << CMTP_LOOPBACK)) {
345                 kfree_skb(skb);
346                 return;
347         }
348 
349         cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
350         appl = CAPIMSG_APPID(skb->data);
351         contr = CAPIMSG_CONTROL(skb->data);
352 
353         application = cmtp_application_get(session, CMTP_MAPPING, appl);
354         if (application) {
355                 appl = application->appl;
356                 CAPIMSG_SETAPPID(skb->data, appl);
357         } else {
358                 BT_ERR("Can't find application with id %d", appl);
359                 kfree_skb(skb);
360                 return;
361         }
362 
363         if ((contr & 0x7f) == 0x01) {
364                 contr = (contr & 0xffffff80) | session->num;
365                 CAPIMSG_SETCONTROL(skb->data, contr);
366         }
367 
368         if (!ctrl) {
369                 BT_ERR("Can't find controller %d for message", session->num);
370                 kfree_skb(skb);
371                 return;
372         }
373 
374         capi_ctr_handle_message(ctrl, appl, skb);
375 }
376 
377 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
378 {
379         BT_DBG("ctrl %p data %p", ctrl, data);
380 
381         return 0;
382 }
383 
384 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
385 {
386         struct cmtp_session *session = ctrl->driverdata;
387 
388         BT_DBG("ctrl %p", ctrl);
389 
390         capi_ctr_reseted(ctrl);
391 
392         atomic_inc(&session->terminate);
393         cmtp_schedule(session);
394 }
395 
396 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
397 {
398         DECLARE_WAITQUEUE(wait, current);
399         struct cmtp_session *session = ctrl->driverdata;
400         struct cmtp_application *application;
401         unsigned long timeo = CMTP_INTEROP_TIMEOUT;
402         unsigned char buf[8];
403         int err = 0, nconn, want = rp->level3cnt;
404 
405         BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
406                 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
407 
408         application = cmtp_application_add(session, appl);
409         if (!application) {
410                 BT_ERR("Can't allocate memory for new application");
411                 return;
412         }
413 
414         if (want < 0)
415                 nconn = ctrl->profile.nbchannel * -want;
416         else
417                 nconn = want;
418 
419         if (nconn == 0)
420                 nconn = ctrl->profile.nbchannel;
421 
422         capimsg_setu16(buf, 0, nconn);
423         capimsg_setu16(buf, 2, rp->datablkcnt);
424         capimsg_setu16(buf, 4, rp->datablklen);
425 
426         application->state = BT_CONFIG;
427         application->msgnum = cmtp_msgnum_get(session);
428 
429         cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
430                                 CAPI_FUNCTION_REGISTER, buf, 6);
431 
432         add_wait_queue(&session->wait, &wait);
433         while (1) {
434                 set_current_state(TASK_INTERRUPTIBLE);
435 
436                 if (!timeo) {
437                         err = -EAGAIN;
438                         break;
439                 }
440 
441                 if (application->state == BT_CLOSED) {
442                         err = -application->err;
443                         break;
444                 }
445 
446                 if (application->state == BT_CONNECTED)
447                         break;
448 
449                 if (signal_pending(current)) {
450                         err = -EINTR;
451                         break;
452                 }
453 
454                 timeo = schedule_timeout(timeo);
455         }
456         set_current_state(TASK_RUNNING);
457         remove_wait_queue(&session->wait, &wait);
458 
459         if (err) {
460                 cmtp_application_del(session, application);
461                 return;
462         }
463 }
464 
465 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
466 {
467         struct cmtp_session *session = ctrl->driverdata;
468         struct cmtp_application *application;
469 
470         BT_DBG("ctrl %p appl %d", ctrl, appl);
471 
472         application = cmtp_application_get(session, CMTP_APPLID, appl);
473         if (!application) {
474                 BT_ERR("Can't find application");
475                 return;
476         }
477 
478         application->msgnum = cmtp_msgnum_get(session);
479 
480         cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
481                                 CAPI_FUNCTION_RELEASE, NULL, 0);
482 
483         wait_event_interruptible_timeout(session->wait,
484                         (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
485 
486         cmtp_application_del(session, application);
487 }
488 
489 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
490 {
491         struct cmtp_session *session = ctrl->driverdata;
492         struct cmtp_application *application;
493         __u16 appl;
494         __u32 contr;
495 
496         BT_DBG("ctrl %p skb %p", ctrl, skb);
497 
498         appl = CAPIMSG_APPID(skb->data);
499         contr = CAPIMSG_CONTROL(skb->data);
500 
501         application = cmtp_application_get(session, CMTP_APPLID, appl);
502         if ((!application) || (application->state != BT_CONNECTED)) {
503                 BT_ERR("Can't find application with id %d", appl);
504                 return CAPI_ILLAPPNR;
505         }
506 
507         CAPIMSG_SETAPPID(skb->data, application->mapping);
508 
509         if ((contr & 0x7f) == session->num) {
510                 contr = (contr & 0xffffff80) | 0x01;
511                 CAPIMSG_SETCONTROL(skb->data, contr);
512         }
513 
514         cmtp_send_capimsg(session, skb);
515 
516         return CAPI_NOERROR;
517 }
518 
519 static char *cmtp_procinfo(struct capi_ctr *ctrl)
520 {
521         return "CAPI Message Transport Protocol";
522 }
523 
524 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
525 {
526         struct cmtp_session *session = ctrl->driverdata;
527         struct cmtp_application *app;
528         struct list_head *p, *n;
529         int len = 0;
530 
531         len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
532         len += sprintf(page + len, "addr %s\n", session->name);
533         len += sprintf(page + len, "ctrl %d\n", session->num);
534 
535         list_for_each_safe(p, n, &session->applications) {
536                 app = list_entry(p, struct cmtp_application, list);
537                 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
538         }
539 
540         if (off + count >= len)
541                 *eof = 1;
542 
543         if (len < off)
544                 return 0;
545 
546         *start = page + off;
547 
548         return ((count < len - off) ? count : len - off);
549 }
550 
551 
552 int cmtp_attach_device(struct cmtp_session *session)
553 {
554         unsigned char buf[4];
555         long ret;
556 
557         BT_DBG("session %p", session);
558 
559         capimsg_setu32(buf, 0, 0);
560 
561         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
562                                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
563 
564         ret = wait_event_interruptible_timeout(session->wait,
565                         session->ncontroller, CMTP_INTEROP_TIMEOUT);
566 
567         BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
568 
569         if (!ret)
570                 return -ETIMEDOUT;
571 
572         if (!session->ncontroller)
573                 return -ENODEV;
574 
575         if (session->ncontroller > 1)
576                 BT_INFO("Setting up only CAPI controller 1");
577 
578         session->ctrl.owner      = THIS_MODULE;
579         session->ctrl.driverdata = session;
580         strcpy(session->ctrl.name, session->name);
581 
582         session->ctrl.driver_name   = "cmtp";
583         session->ctrl.load_firmware = cmtp_load_firmware;
584         session->ctrl.reset_ctr     = cmtp_reset_ctr;
585         session->ctrl.register_appl = cmtp_register_appl;
586         session->ctrl.release_appl  = cmtp_release_appl;
587         session->ctrl.send_message  = cmtp_send_message;
588 
589         session->ctrl.procinfo      = cmtp_procinfo;
590         session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
591 
592         if (attach_capi_ctr(&session->ctrl) < 0) {
593                 BT_ERR("Can't attach new controller");
594                 return -EBUSY;
595         }
596 
597         session->num = session->ctrl.cnr;
598 
599         BT_DBG("session %p num %d", session, session->num);
600 
601         capimsg_setu32(buf, 0, 1);
602 
603         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
604                                 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
605 
606         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
607                                 CAPI_FUNCTION_GET_VERSION, buf, 4);
608 
609         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
610                                 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
611 
612         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
613                                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
614 
615         return 0;
616 }
617 
618 void cmtp_detach_device(struct cmtp_session *session)
619 {
620         BT_DBG("session %p", session);
621 
622         detach_capi_ctr(&session->ctrl);
623 }
624 
  This page was automatically generated by the LXR engine.