blob: 67cff810c77d19c4755634d7cf4f3093a68f0d9a [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>
Alexey Dobriyan9a58a802010-01-14 03:10:54 -080024#include <linux/proc_fs.h>
25#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/sched.h>
30#include <linux/slab.h>
31#include <linux/poll.h>
32#include <linux/fcntl.h>
33#include <linux/skbuff.h>
34#include <linux/socket.h>
35#include <linux/ioctl.h>
36#include <linux/file.h>
37#include <linux/wait.h>
38#include <net/sock.h>
39
40#include <linux/isdn/capilli.h>
41#include <linux/isdn/capicmd.h>
42#include <linux/isdn/capiutil.h>
43
44#include "cmtp.h"
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define CAPI_INTEROPERABILITY 0x20
47
48#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
49#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
50#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
51#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
52
53#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
54#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
55#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
56#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
57
58#define CAPI_FUNCTION_REGISTER 0
59#define CAPI_FUNCTION_RELEASE 1
60#define CAPI_FUNCTION_GET_PROFILE 2
61#define CAPI_FUNCTION_GET_MANUFACTURER 3
62#define CAPI_FUNCTION_GET_VERSION 4
63#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
64#define CAPI_FUNCTION_MANUFACTURER 6
65#define CAPI_FUNCTION_LOOPBACK 7
66
67
68#define CMTP_MSGNUM 1
69#define CMTP_APPLID 2
70#define CMTP_MAPPING 3
71
72static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
73{
Marcel Holtmann25ea6db2006-07-06 15:40:09 +020074 struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 BT_DBG("session %p application %p appl %d", session, app, appl);
77
78 if (!app)
79 return NULL;
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 app->state = BT_OPEN;
82 app->appl = appl;
83
84 list_add_tail(&app->list, &session->applications);
85
86 return app;
87}
88
89static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
90{
91 BT_DBG("session %p application %p", session, app);
92
93 if (app) {
94 list_del(&app->list);
95 kfree(app);
96 }
97}
98
99static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
100{
101 struct cmtp_application *app;
102 struct list_head *p, *n;
103
104 list_for_each_safe(p, n, &session->applications) {
105 app = list_entry(p, struct cmtp_application, list);
106 switch (pattern) {
107 case CMTP_MSGNUM:
108 if (app->msgnum == value)
109 return app;
110 break;
111 case CMTP_APPLID:
112 if (app->appl == value)
113 return app;
114 break;
115 case CMTP_MAPPING:
116 if (app->mapping == value)
117 return app;
118 break;
119 }
120 }
121
122 return NULL;
123}
124
125static int cmtp_msgnum_get(struct cmtp_session *session)
126{
127 session->msgnum++;
128
129 if ((session->msgnum & 0xff) > 200)
130 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
131
132 return session->msgnum;
133}
134
135static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
136{
137 struct cmtp_scb *scb = (void *) skb->cb;
138
139 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
140
141 scb->id = -1;
142 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
143
144 skb_queue_tail(&session->transmit, skb);
145
146 cmtp_schedule(session);
147}
148
149static void cmtp_send_interopmsg(struct cmtp_session *session,
150 __u8 subcmd, __u16 appl, __u16 msgnum,
151 __u16 function, unsigned char *buf, int len)
152{
153 struct sk_buff *skb;
154 unsigned char *s;
155
156 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
157
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200158 skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
159 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 BT_ERR("Can't allocate memory for interoperability packet");
161 return;
162 }
163
164 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
165
166 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
167 capimsg_setu16(s, 2, appl);
168 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
169 capimsg_setu8 (s, 5, subcmd);
170 capimsg_setu16(s, 6, msgnum);
171
172 /* Interoperability selector (Bluetooth Device Management) */
173 capimsg_setu16(s, 8, 0x0001);
174
175 capimsg_setu8 (s, 10, 3 + len);
176 capimsg_setu16(s, 11, function);
177 capimsg_setu8 (s, 13, len);
178
179 if (len > 0)
180 memcpy(s + 14, buf, len);
181
182 cmtp_send_capimsg(session, skb);
183}
184
185static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
186{
187 struct capi_ctr *ctrl = &session->ctrl;
188 struct cmtp_application *application;
189 __u16 appl, msgnum, func, info;
190 __u32 controller;
191
192 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
193
194 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
195 case CAPI_CONF:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100196 if (skb->len < CAPI_MSG_BASELEN + 10)
197 break;
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
200 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
201
202 switch (func) {
203 case CAPI_FUNCTION_REGISTER:
204 msgnum = CAPIMSG_MSGID(skb->data);
205
206 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
207 if (application) {
208 application->state = BT_CONNECTED;
209 application->msgnum = 0;
210 application->mapping = CAPIMSG_APPID(skb->data);
211 wake_up_interruptible(&session->wait);
212 }
213
214 break;
215
216 case CAPI_FUNCTION_RELEASE:
217 appl = CAPIMSG_APPID(skb->data);
218
219 application = cmtp_application_get(session, CMTP_MAPPING, appl);
220 if (application) {
221 application->state = BT_CLOSED;
222 application->msgnum = 0;
223 wake_up_interruptible(&session->wait);
224 }
225
226 break;
227
228 case CAPI_FUNCTION_GET_PROFILE:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100229 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
230 break;
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
233 msgnum = CAPIMSG_MSGID(skb->data);
234
235 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
236 session->ncontroller = controller;
237 wake_up_interruptible(&session->wait);
238 break;
239 }
240
241 if (!info && ctrl) {
242 memcpy(&ctrl->profile,
243 skb->data + CAPI_MSG_BASELEN + 11,
244 sizeof(capi_profile));
245 session->state = BT_CONNECTED;
246 capi_ctr_ready(ctrl);
247 }
248
249 break;
250
251 case CAPI_FUNCTION_GET_MANUFACTURER:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100252 if (skb->len < CAPI_MSG_BASELEN + 15)
253 break;
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
256
257 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100258 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
259 skb->data[CAPI_MSG_BASELEN + 14]);
260
261 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 strncpy(ctrl->manu,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100263 skb->data + CAPI_MSG_BASELEN + 15, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 }
265
266 break;
267
268 case CAPI_FUNCTION_GET_VERSION:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100269 if (skb->len < CAPI_MSG_BASELEN + 32)
270 break;
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
273
274 if (!info && ctrl) {
275 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
276 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
277 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
278 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
279 }
280
281 break;
282
283 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100284 if (skb->len < CAPI_MSG_BASELEN + 17)
285 break;
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
288
289 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100290 int len = min_t(uint, CAPI_SERIAL_LEN,
291 skb->data[CAPI_MSG_BASELEN + 16]);
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
294 strncpy(ctrl->serial,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100295 skb->data + CAPI_MSG_BASELEN + 17, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
297
298 break;
299 }
300
301 break;
302
303 case CAPI_IND:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100304 if (skb->len < CAPI_MSG_BASELEN + 6)
305 break;
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
308
309 if (func == CAPI_FUNCTION_LOOPBACK) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100310 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
311 skb->data[CAPI_MSG_BASELEN + 5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 appl = CAPIMSG_APPID(skb->data);
313 msgnum = CAPIMSG_MSGID(skb->data);
314 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100315 skb->data + CAPI_MSG_BASELEN + 6, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 }
317
318 break;
319 }
320
321 kfree_skb(skb);
322}
323
324void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
325{
326 struct capi_ctr *ctrl = &session->ctrl;
327 struct cmtp_application *application;
328 __u16 cmd, appl;
329 __u32 contr;
330
331 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
332
Marcel Holtmannf4777562007-01-08 02:16:23 +0100333 if (skb->len < CAPI_MSG_BASELEN)
334 return;
335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
337 cmtp_recv_interopmsg(session, skb);
338 return;
339 }
340
341 if (session->flags & (1 << CMTP_LOOPBACK)) {
342 kfree_skb(skb);
343 return;
344 }
345
346 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
347 appl = CAPIMSG_APPID(skb->data);
348 contr = CAPIMSG_CONTROL(skb->data);
349
350 application = cmtp_application_get(session, CMTP_MAPPING, appl);
351 if (application) {
352 appl = application->appl;
353 CAPIMSG_SETAPPID(skb->data, appl);
354 } else {
355 BT_ERR("Can't find application with id %d", appl);
356 kfree_skb(skb);
357 return;
358 }
359
360 if ((contr & 0x7f) == 0x01) {
361 contr = (contr & 0xffffff80) | session->num;
362 CAPIMSG_SETCONTROL(skb->data, contr);
363 }
364
365 if (!ctrl) {
366 BT_ERR("Can't find controller %d for message", session->num);
367 kfree_skb(skb);
368 return;
369 }
370
371 capi_ctr_handle_message(ctrl, appl, skb);
372}
373
374static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
375{
376 BT_DBG("ctrl %p data %p", ctrl, data);
377
378 return 0;
379}
380
381static void cmtp_reset_ctr(struct capi_ctr *ctrl)
382{
383 struct cmtp_session *session = ctrl->driverdata;
384
385 BT_DBG("ctrl %p", ctrl);
386
Tilman Schmidt4e329972009-06-07 09:09:23 +0000387 capi_ctr_down(ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 atomic_inc(&session->terminate);
390 cmtp_schedule(session);
391}
392
393static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
394{
395 DECLARE_WAITQUEUE(wait, current);
396 struct cmtp_session *session = ctrl->driverdata;
397 struct cmtp_application *application;
398 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
399 unsigned char buf[8];
400 int err = 0, nconn, want = rp->level3cnt;
401
402 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
403 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
404
405 application = cmtp_application_add(session, appl);
406 if (!application) {
407 BT_ERR("Can't allocate memory for new application");
408 return;
409 }
410
411 if (want < 0)
412 nconn = ctrl->profile.nbchannel * -want;
413 else
414 nconn = want;
415
416 if (nconn == 0)
417 nconn = ctrl->profile.nbchannel;
418
419 capimsg_setu16(buf, 0, nconn);
420 capimsg_setu16(buf, 2, rp->datablkcnt);
421 capimsg_setu16(buf, 4, rp->datablklen);
422
423 application->state = BT_CONFIG;
424 application->msgnum = cmtp_msgnum_get(session);
425
426 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
427 CAPI_FUNCTION_REGISTER, buf, 6);
428
429 add_wait_queue(&session->wait, &wait);
430 while (1) {
431 set_current_state(TASK_INTERRUPTIBLE);
432
433 if (!timeo) {
434 err = -EAGAIN;
435 break;
436 }
437
438 if (application->state == BT_CLOSED) {
439 err = -application->err;
440 break;
441 }
442
443 if (application->state == BT_CONNECTED)
444 break;
445
446 if (signal_pending(current)) {
447 err = -EINTR;
448 break;
449 }
450
451 timeo = schedule_timeout(timeo);
452 }
453 set_current_state(TASK_RUNNING);
454 remove_wait_queue(&session->wait, &wait);
455
456 if (err) {
457 cmtp_application_del(session, application);
458 return;
459 }
460}
461
462static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
463{
464 struct cmtp_session *session = ctrl->driverdata;
465 struct cmtp_application *application;
466
467 BT_DBG("ctrl %p appl %d", ctrl, appl);
468
469 application = cmtp_application_get(session, CMTP_APPLID, appl);
470 if (!application) {
471 BT_ERR("Can't find application");
472 return;
473 }
474
475 application->msgnum = cmtp_msgnum_get(session);
476
477 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
478 CAPI_FUNCTION_RELEASE, NULL, 0);
479
480 wait_event_interruptible_timeout(session->wait,
481 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
482
483 cmtp_application_del(session, application);
484}
485
486static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
487{
488 struct cmtp_session *session = ctrl->driverdata;
489 struct cmtp_application *application;
490 __u16 appl;
491 __u32 contr;
492
493 BT_DBG("ctrl %p skb %p", ctrl, skb);
494
495 appl = CAPIMSG_APPID(skb->data);
496 contr = CAPIMSG_CONTROL(skb->data);
497
498 application = cmtp_application_get(session, CMTP_APPLID, appl);
499 if ((!application) || (application->state != BT_CONNECTED)) {
500 BT_ERR("Can't find application with id %d", appl);
501 return CAPI_ILLAPPNR;
502 }
503
504 CAPIMSG_SETAPPID(skb->data, application->mapping);
505
506 if ((contr & 0x7f) == session->num) {
507 contr = (contr & 0xffffff80) | 0x01;
508 CAPIMSG_SETCONTROL(skb->data, contr);
509 }
510
511 cmtp_send_capimsg(session, skb);
512
513 return CAPI_NOERROR;
514}
515
516static char *cmtp_procinfo(struct capi_ctr *ctrl)
517{
518 return "CAPI Message Transport Protocol";
519}
520
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800521static int cmtp_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800523 struct capi_ctr *ctrl = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 struct cmtp_session *session = ctrl->driverdata;
525 struct cmtp_application *app;
526 struct list_head *p, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800528 seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
529 seq_printf(m, "addr %s\n", session->name);
530 seq_printf(m, "ctrl %d\n", session->num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 list_for_each_safe(p, n, &session->applications) {
533 app = list_entry(p, struct cmtp_application, list);
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800534 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
536
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800537 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800540static int cmtp_proc_open(struct inode *inode, struct file *file)
541{
542 return single_open(file, cmtp_proc_show, PDE(inode)->data);
543}
544
545static const struct file_operations cmtp_proc_fops = {
546 .owner = THIS_MODULE,
547 .open = cmtp_proc_open,
548 .read = seq_read,
549 .llseek = seq_lseek,
550 .release = single_release,
551};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553int cmtp_attach_device(struct cmtp_session *session)
554{
555 unsigned char buf[4];
556 long ret;
557
558 BT_DBG("session %p", session);
559
560 capimsg_setu32(buf, 0, 0);
561
562 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
563 CAPI_FUNCTION_GET_PROFILE, buf, 4);
564
565 ret = wait_event_interruptible_timeout(session->wait,
566 session->ncontroller, CMTP_INTEROP_TIMEOUT);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
569
570 if (!ret)
571 return -ETIMEDOUT;
572
573 if (!session->ncontroller)
574 return -ENODEV;
575
576 if (session->ncontroller > 1)
577 BT_INFO("Setting up only CAPI controller 1");
578
579 session->ctrl.owner = THIS_MODULE;
580 session->ctrl.driverdata = session;
581 strcpy(session->ctrl.name, session->name);
582
583 session->ctrl.driver_name = "cmtp";
584 session->ctrl.load_firmware = cmtp_load_firmware;
585 session->ctrl.reset_ctr = cmtp_reset_ctr;
586 session->ctrl.register_appl = cmtp_register_appl;
587 session->ctrl.release_appl = cmtp_release_appl;
588 session->ctrl.send_message = cmtp_send_message;
589
590 session->ctrl.procinfo = cmtp_procinfo;
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800591 session->ctrl.proc_fops = &cmtp_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 if (attach_capi_ctr(&session->ctrl) < 0) {
594 BT_ERR("Can't attach new controller");
595 return -EBUSY;
596 }
597
598 session->num = session->ctrl.cnr;
599
600 BT_DBG("session %p num %d", session, session->num);
601
602 capimsg_setu32(buf, 0, 1);
603
604 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
605 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
606
607 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
608 CAPI_FUNCTION_GET_VERSION, buf, 4);
609
610 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
611 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
612
613 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
614 CAPI_FUNCTION_GET_PROFILE, buf, 4);
615
616 return 0;
617}
618
619void cmtp_detach_device(struct cmtp_session *session)
620{
621 BT_DBG("session %p", session);
622
623 detach_capi_ctr(&session->ctrl);
624}