blob: 3487cfe74aecad8d69f007db8e23537226ff3d3a [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
158 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
159 BT_ERR("Can't allocate memory for interoperability packet");
160 return;
161 }
162
163 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
164
165 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
166 capimsg_setu16(s, 2, appl);
167 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
168 capimsg_setu8 (s, 5, subcmd);
169 capimsg_setu16(s, 6, msgnum);
170
171 /* Interoperability selector (Bluetooth Device Management) */
172 capimsg_setu16(s, 8, 0x0001);
173
174 capimsg_setu8 (s, 10, 3 + len);
175 capimsg_setu16(s, 11, function);
176 capimsg_setu8 (s, 13, len);
177
178 if (len > 0)
179 memcpy(s + 14, buf, len);
180
181 cmtp_send_capimsg(session, skb);
182}
183
184static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
185{
186 struct capi_ctr *ctrl = &session->ctrl;
187 struct cmtp_application *application;
188 __u16 appl, msgnum, func, info;
189 __u32 controller;
190
191 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
192
193 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
194 case CAPI_CONF:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100195 if (skb->len < CAPI_MSG_BASELEN + 10)
196 break;
197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
199 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
200
201 switch (func) {
202 case CAPI_FUNCTION_REGISTER:
203 msgnum = CAPIMSG_MSGID(skb->data);
204
205 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
206 if (application) {
207 application->state = BT_CONNECTED;
208 application->msgnum = 0;
209 application->mapping = CAPIMSG_APPID(skb->data);
210 wake_up_interruptible(&session->wait);
211 }
212
213 break;
214
215 case CAPI_FUNCTION_RELEASE:
216 appl = CAPIMSG_APPID(skb->data);
217
218 application = cmtp_application_get(session, CMTP_MAPPING, appl);
219 if (application) {
220 application->state = BT_CLOSED;
221 application->msgnum = 0;
222 wake_up_interruptible(&session->wait);
223 }
224
225 break;
226
227 case CAPI_FUNCTION_GET_PROFILE:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100228 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
229 break;
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
232 msgnum = CAPIMSG_MSGID(skb->data);
233
234 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
235 session->ncontroller = controller;
236 wake_up_interruptible(&session->wait);
237 break;
238 }
239
240 if (!info && ctrl) {
241 memcpy(&ctrl->profile,
242 skb->data + CAPI_MSG_BASELEN + 11,
243 sizeof(capi_profile));
244 session->state = BT_CONNECTED;
245 capi_ctr_ready(ctrl);
246 }
247
248 break;
249
250 case CAPI_FUNCTION_GET_MANUFACTURER:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100251 if (skb->len < CAPI_MSG_BASELEN + 15)
252 break;
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
255
256 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100257 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
258 skb->data[CAPI_MSG_BASELEN + 14]);
259
260 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 strncpy(ctrl->manu,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100262 skb->data + CAPI_MSG_BASELEN + 15, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 }
264
265 break;
266
267 case CAPI_FUNCTION_GET_VERSION:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100268 if (skb->len < CAPI_MSG_BASELEN + 32)
269 break;
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
272
273 if (!info && ctrl) {
274 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
275 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
276 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
277 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
278 }
279
280 break;
281
282 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100283 if (skb->len < CAPI_MSG_BASELEN + 17)
284 break;
285
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
287
288 if (!info && ctrl) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100289 int len = min_t(uint, CAPI_SERIAL_LEN,
290 skb->data[CAPI_MSG_BASELEN + 16]);
291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
293 strncpy(ctrl->serial,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100294 skb->data + CAPI_MSG_BASELEN + 17, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296
297 break;
298 }
299
300 break;
301
302 case CAPI_IND:
Marcel Holtmannf4777562007-01-08 02:16:23 +0100303 if (skb->len < CAPI_MSG_BASELEN + 6)
304 break;
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
307
308 if (func == CAPI_FUNCTION_LOOPBACK) {
Marcel Holtmannf4777562007-01-08 02:16:23 +0100309 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
310 skb->data[CAPI_MSG_BASELEN + 5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 appl = CAPIMSG_APPID(skb->data);
312 msgnum = CAPIMSG_MSGID(skb->data);
313 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
Marcel Holtmannf4777562007-01-08 02:16:23 +0100314 skb->data + CAPI_MSG_BASELEN + 6, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
316
317 break;
318 }
319
320 kfree_skb(skb);
321}
322
323void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
324{
325 struct capi_ctr *ctrl = &session->ctrl;
326 struct cmtp_application *application;
327 __u16 cmd, appl;
328 __u32 contr;
329
330 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
331
Marcel Holtmannf4777562007-01-08 02:16:23 +0100332 if (skb->len < CAPI_MSG_BASELEN)
333 return;
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
336 cmtp_recv_interopmsg(session, skb);
337 return;
338 }
339
340 if (session->flags & (1 << CMTP_LOOPBACK)) {
341 kfree_skb(skb);
342 return;
343 }
344
345 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
346 appl = CAPIMSG_APPID(skb->data);
347 contr = CAPIMSG_CONTROL(skb->data);
348
349 application = cmtp_application_get(session, CMTP_MAPPING, appl);
350 if (application) {
351 appl = application->appl;
352 CAPIMSG_SETAPPID(skb->data, appl);
353 } else {
354 BT_ERR("Can't find application with id %d", appl);
355 kfree_skb(skb);
356 return;
357 }
358
359 if ((contr & 0x7f) == 0x01) {
360 contr = (contr & 0xffffff80) | session->num;
361 CAPIMSG_SETCONTROL(skb->data, contr);
362 }
363
364 if (!ctrl) {
365 BT_ERR("Can't find controller %d for message", session->num);
366 kfree_skb(skb);
367 return;
368 }
369
370 capi_ctr_handle_message(ctrl, appl, skb);
371}
372
373static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
374{
375 BT_DBG("ctrl %p data %p", ctrl, data);
376
377 return 0;
378}
379
380static void cmtp_reset_ctr(struct capi_ctr *ctrl)
381{
382 struct cmtp_session *session = ctrl->driverdata;
383
384 BT_DBG("ctrl %p", ctrl);
385
Tilman Schmidt4e329972009-06-07 09:09:23 +0000386 capi_ctr_down(ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 atomic_inc(&session->terminate);
389 cmtp_schedule(session);
390}
391
392static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
393{
394 DECLARE_WAITQUEUE(wait, current);
395 struct cmtp_session *session = ctrl->driverdata;
396 struct cmtp_application *application;
397 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
398 unsigned char buf[8];
399 int err = 0, nconn, want = rp->level3cnt;
400
401 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
402 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
403
404 application = cmtp_application_add(session, appl);
405 if (!application) {
406 BT_ERR("Can't allocate memory for new application");
407 return;
408 }
409
410 if (want < 0)
411 nconn = ctrl->profile.nbchannel * -want;
412 else
413 nconn = want;
414
415 if (nconn == 0)
416 nconn = ctrl->profile.nbchannel;
417
418 capimsg_setu16(buf, 0, nconn);
419 capimsg_setu16(buf, 2, rp->datablkcnt);
420 capimsg_setu16(buf, 4, rp->datablklen);
421
422 application->state = BT_CONFIG;
423 application->msgnum = cmtp_msgnum_get(session);
424
425 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
426 CAPI_FUNCTION_REGISTER, buf, 6);
427
428 add_wait_queue(&session->wait, &wait);
429 while (1) {
430 set_current_state(TASK_INTERRUPTIBLE);
431
432 if (!timeo) {
433 err = -EAGAIN;
434 break;
435 }
436
437 if (application->state == BT_CLOSED) {
438 err = -application->err;
439 break;
440 }
441
442 if (application->state == BT_CONNECTED)
443 break;
444
445 if (signal_pending(current)) {
446 err = -EINTR;
447 break;
448 }
449
450 timeo = schedule_timeout(timeo);
451 }
452 set_current_state(TASK_RUNNING);
453 remove_wait_queue(&session->wait, &wait);
454
455 if (err) {
456 cmtp_application_del(session, application);
457 return;
458 }
459}
460
461static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
462{
463 struct cmtp_session *session = ctrl->driverdata;
464 struct cmtp_application *application;
465
466 BT_DBG("ctrl %p appl %d", ctrl, appl);
467
468 application = cmtp_application_get(session, CMTP_APPLID, appl);
469 if (!application) {
470 BT_ERR("Can't find application");
471 return;
472 }
473
474 application->msgnum = cmtp_msgnum_get(session);
475
476 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
477 CAPI_FUNCTION_RELEASE, NULL, 0);
478
479 wait_event_interruptible_timeout(session->wait,
480 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
481
482 cmtp_application_del(session, application);
483}
484
485static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
486{
487 struct cmtp_session *session = ctrl->driverdata;
488 struct cmtp_application *application;
489 __u16 appl;
490 __u32 contr;
491
492 BT_DBG("ctrl %p skb %p", ctrl, skb);
493
494 appl = CAPIMSG_APPID(skb->data);
495 contr = CAPIMSG_CONTROL(skb->data);
496
497 application = cmtp_application_get(session, CMTP_APPLID, appl);
498 if ((!application) || (application->state != BT_CONNECTED)) {
499 BT_ERR("Can't find application with id %d", appl);
500 return CAPI_ILLAPPNR;
501 }
502
503 CAPIMSG_SETAPPID(skb->data, application->mapping);
504
505 if ((contr & 0x7f) == session->num) {
506 contr = (contr & 0xffffff80) | 0x01;
507 CAPIMSG_SETCONTROL(skb->data, contr);
508 }
509
510 cmtp_send_capimsg(session, skb);
511
512 return CAPI_NOERROR;
513}
514
515static char *cmtp_procinfo(struct capi_ctr *ctrl)
516{
517 return "CAPI Message Transport Protocol";
518}
519
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800520static int cmtp_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800522 struct capi_ctr *ctrl = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 struct cmtp_session *session = ctrl->driverdata;
524 struct cmtp_application *app;
525 struct list_head *p, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800527 seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
528 seq_printf(m, "addr %s\n", session->name);
529 seq_printf(m, "ctrl %d\n", session->num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 list_for_each_safe(p, n, &session->applications) {
532 app = list_entry(p, struct cmtp_application, list);
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800533 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
535
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800536 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800539static int cmtp_proc_open(struct inode *inode, struct file *file)
540{
541 return single_open(file, cmtp_proc_show, PDE(inode)->data);
542}
543
544static const struct file_operations cmtp_proc_fops = {
545 .owner = THIS_MODULE,
546 .open = cmtp_proc_open,
547 .read = seq_read,
548 .llseek = seq_lseek,
549 .release = single_release,
550};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
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;
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800590 session->ctrl.proc_fops = &cmtp_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
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}