blob: 3e9d5bb3fefb6de364353c62684efd5b7629e9d4 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 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
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090013 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 SOFTWARE IS DISCLAIMED.
21*/
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/types.h>
26#include <linux/errno.h>
27#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#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
76static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
77{
Marcel Holtmann25ea6db2006-07-06 15:40:09 +020078 struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 BT_DBG("session %p application %p appl %d", session, app, appl);
81
82 if (!app)
83 return NULL;
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 app->state = BT_OPEN;
86 app->appl = appl;
87
88 list_add_tail(&app->list, &session->applications);
89
90 return app;
91}
92
93static 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
103static 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
129static 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
139static 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
153static 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
188static 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:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100199 if (skb->len < CAPI_MSG_BASELEN + 10)
200 break;
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 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:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100232 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
233 break;
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 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:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100255 if (skb->len < CAPI_MSG_BASELEN + 15)
256 break;
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
259
260 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100261 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
262 skb->data[CAPI_MSG_BASELEN + 14]);
263
264 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 strncpy(ctrl->manu,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100266 skb->data + CAPI_MSG_BASELEN + 15, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 }
268
269 break;
270
271 case CAPI_FUNCTION_GET_VERSION:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100272 if (skb->len < CAPI_MSG_BASELEN + 32)
273 break;
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 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:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100287 if (skb->len < CAPI_MSG_BASELEN + 17)
288 break;
289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
291
292 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100293 int len = min_t(uint, CAPI_SERIAL_LEN,
294 skb->data[CAPI_MSG_BASELEN + 16]);
295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
297 strncpy(ctrl->serial,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100298 skb->data + CAPI_MSG_BASELEN + 17, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
301 break;
302 }
303
304 break;
305
306 case CAPI_IND:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100307 if (skb->len < CAPI_MSG_BASELEN + 6)
308 break;
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
311
312 if (func == CAPI_FUNCTION_LOOPBACK) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100313 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
314 skb->data[CAPI_MSG_BASELEN + 5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 appl = CAPIMSG_APPID(skb->data);
316 msgnum = CAPIMSG_MSGID(skb->data);
317 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100318 skb->data + CAPI_MSG_BASELEN + 6, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 }
320
321 break;
322 }
323
324 kfree_skb(skb);
325}
326
327void 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
Marcel Holtmannf4777562007-01-08 02:16:23 +0100336 if (skb->len < CAPI_MSG_BASELEN)
337 return;
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 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
377static 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
384static 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
396static 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
465static 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
489static 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
519static char *cmtp_procinfo(struct capi_ctr *ctrl)
520{
521 return "CAPI Message Transport Protocol";
522}
523
524static 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
552int 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);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 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
618void cmtp_detach_device(struct cmtp_session *session)
619{
620 BT_DBG("session %p", session);
621
622 detach_capi_ctr(&session->ctrl);
623}