[ARM] Support register switch in nommu mode
[linux-2.6/verdex.git] / net / bluetooth / cmtp / capi.c
blobb2e7e38531c602c72580570c331f1b3e6328536f
1 /*
2 CMTP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
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;
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.
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.
23 #include <linux/config.h>
24 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #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>
40 #include <linux/isdn/capilli.h>
41 #include <linux/isdn/capicmd.h>
42 #include <linux/isdn/capiutil.h>
44 #include "cmtp.h"
46 #ifndef CONFIG_BT_CMTP_DEBUG
47 #undef BT_DBG
48 #define BT_DBG(D...)
49 #endif
51 #define CAPI_INTEROPERABILITY 0x20
53 #define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
54 #define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
55 #define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
56 #define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
58 #define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
59 #define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
60 #define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
61 #define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
63 #define CAPI_FUNCTION_REGISTER 0
64 #define CAPI_FUNCTION_RELEASE 1
65 #define CAPI_FUNCTION_GET_PROFILE 2
66 #define CAPI_FUNCTION_GET_MANUFACTURER 3
67 #define CAPI_FUNCTION_GET_VERSION 4
68 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
69 #define CAPI_FUNCTION_MANUFACTURER 6
70 #define CAPI_FUNCTION_LOOPBACK 7
73 #define CMTP_MSGNUM 1
74 #define CMTP_APPLID 2
75 #define CMTP_MAPPING 3
77 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
79 struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
81 BT_DBG("session %p application %p appl %d", session, app, appl);
83 if (!app)
84 return NULL;
86 memset(app, 0, sizeof(*app));
88 app->state = BT_OPEN;
89 app->appl = appl;
91 list_add_tail(&app->list, &session->applications);
93 return app;
96 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
98 BT_DBG("session %p application %p", session, app);
100 if (app) {
101 list_del(&app->list);
102 kfree(app);
106 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
108 struct cmtp_application *app;
109 struct list_head *p, *n;
111 list_for_each_safe(p, n, &session->applications) {
112 app = list_entry(p, struct cmtp_application, list);
113 switch (pattern) {
114 case CMTP_MSGNUM:
115 if (app->msgnum == value)
116 return app;
117 break;
118 case CMTP_APPLID:
119 if (app->appl == value)
120 return app;
121 break;
122 case CMTP_MAPPING:
123 if (app->mapping == value)
124 return app;
125 break;
129 return NULL;
132 static int cmtp_msgnum_get(struct cmtp_session *session)
134 session->msgnum++;
136 if ((session->msgnum & 0xff) > 200)
137 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
139 return session->msgnum;
142 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
144 struct cmtp_scb *scb = (void *) skb->cb;
146 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
148 scb->id = -1;
149 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
151 skb_queue_tail(&session->transmit, skb);
153 cmtp_schedule(session);
156 static void cmtp_send_interopmsg(struct cmtp_session *session,
157 __u8 subcmd, __u16 appl, __u16 msgnum,
158 __u16 function, unsigned char *buf, int len)
160 struct sk_buff *skb;
161 unsigned char *s;
163 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
165 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
166 BT_ERR("Can't allocate memory for interoperability packet");
167 return;
170 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
172 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
173 capimsg_setu16(s, 2, appl);
174 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
175 capimsg_setu8 (s, 5, subcmd);
176 capimsg_setu16(s, 6, msgnum);
178 /* Interoperability selector (Bluetooth Device Management) */
179 capimsg_setu16(s, 8, 0x0001);
181 capimsg_setu8 (s, 10, 3 + len);
182 capimsg_setu16(s, 11, function);
183 capimsg_setu8 (s, 13, len);
185 if (len > 0)
186 memcpy(s + 14, buf, len);
188 cmtp_send_capimsg(session, skb);
191 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
193 struct capi_ctr *ctrl = &session->ctrl;
194 struct cmtp_application *application;
195 __u16 appl, msgnum, func, info;
196 __u32 controller;
198 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
200 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
201 case CAPI_CONF:
202 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
203 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
205 switch (func) {
206 case CAPI_FUNCTION_REGISTER:
207 msgnum = CAPIMSG_MSGID(skb->data);
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);
217 break;
219 case CAPI_FUNCTION_RELEASE:
220 appl = CAPIMSG_APPID(skb->data);
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);
229 break;
231 case CAPI_FUNCTION_GET_PROFILE:
232 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
233 msgnum = CAPIMSG_MSGID(skb->data);
235 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
236 session->ncontroller = controller;
237 wake_up_interruptible(&session->wait);
238 break;
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);
249 break;
251 case CAPI_FUNCTION_GET_MANUFACTURER:
252 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
254 if (!info && ctrl) {
255 strncpy(ctrl->manu,
256 skb->data + CAPI_MSG_BASELEN + 15,
257 skb->data[CAPI_MSG_BASELEN + 14]);
260 break;
262 case CAPI_FUNCTION_GET_VERSION:
263 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
265 if (!info && ctrl) {
266 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
267 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
268 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
269 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
272 break;
274 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
275 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
277 if (!info && ctrl) {
278 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
279 strncpy(ctrl->serial,
280 skb->data + CAPI_MSG_BASELEN + 17,
281 skb->data[CAPI_MSG_BASELEN + 16]);
284 break;
287 break;
289 case CAPI_IND:
290 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
292 if (func == CAPI_FUNCTION_LOOPBACK) {
293 appl = CAPIMSG_APPID(skb->data);
294 msgnum = CAPIMSG_MSGID(skb->data);
295 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
296 skb->data + CAPI_MSG_BASELEN + 6,
297 skb->data[CAPI_MSG_BASELEN + 5]);
300 break;
303 kfree_skb(skb);
306 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
308 struct capi_ctr *ctrl = &session->ctrl;
309 struct cmtp_application *application;
310 __u16 cmd, appl;
311 __u32 contr;
313 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
315 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
316 cmtp_recv_interopmsg(session, skb);
317 return;
320 if (session->flags & (1 << CMTP_LOOPBACK)) {
321 kfree_skb(skb);
322 return;
325 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
326 appl = CAPIMSG_APPID(skb->data);
327 contr = CAPIMSG_CONTROL(skb->data);
329 application = cmtp_application_get(session, CMTP_MAPPING, appl);
330 if (application) {
331 appl = application->appl;
332 CAPIMSG_SETAPPID(skb->data, appl);
333 } else {
334 BT_ERR("Can't find application with id %d", appl);
335 kfree_skb(skb);
336 return;
339 if ((contr & 0x7f) == 0x01) {
340 contr = (contr & 0xffffff80) | session->num;
341 CAPIMSG_SETCONTROL(skb->data, contr);
344 if (!ctrl) {
345 BT_ERR("Can't find controller %d for message", session->num);
346 kfree_skb(skb);
347 return;
350 capi_ctr_handle_message(ctrl, appl, skb);
353 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
355 BT_DBG("ctrl %p data %p", ctrl, data);
357 return 0;
360 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
362 struct cmtp_session *session = ctrl->driverdata;
364 BT_DBG("ctrl %p", ctrl);
366 capi_ctr_reseted(ctrl);
368 atomic_inc(&session->terminate);
369 cmtp_schedule(session);
372 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
374 DECLARE_WAITQUEUE(wait, current);
375 struct cmtp_session *session = ctrl->driverdata;
376 struct cmtp_application *application;
377 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
378 unsigned char buf[8];
379 int err = 0, nconn, want = rp->level3cnt;
381 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
382 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
384 application = cmtp_application_add(session, appl);
385 if (!application) {
386 BT_ERR("Can't allocate memory for new application");
387 return;
390 if (want < 0)
391 nconn = ctrl->profile.nbchannel * -want;
392 else
393 nconn = want;
395 if (nconn == 0)
396 nconn = ctrl->profile.nbchannel;
398 capimsg_setu16(buf, 0, nconn);
399 capimsg_setu16(buf, 2, rp->datablkcnt);
400 capimsg_setu16(buf, 4, rp->datablklen);
402 application->state = BT_CONFIG;
403 application->msgnum = cmtp_msgnum_get(session);
405 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
406 CAPI_FUNCTION_REGISTER, buf, 6);
408 add_wait_queue(&session->wait, &wait);
409 while (1) {
410 set_current_state(TASK_INTERRUPTIBLE);
412 if (!timeo) {
413 err = -EAGAIN;
414 break;
417 if (application->state == BT_CLOSED) {
418 err = -application->err;
419 break;
422 if (application->state == BT_CONNECTED)
423 break;
425 if (signal_pending(current)) {
426 err = -EINTR;
427 break;
430 timeo = schedule_timeout(timeo);
432 set_current_state(TASK_RUNNING);
433 remove_wait_queue(&session->wait, &wait);
435 if (err) {
436 cmtp_application_del(session, application);
437 return;
441 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
443 struct cmtp_session *session = ctrl->driverdata;
444 struct cmtp_application *application;
446 BT_DBG("ctrl %p appl %d", ctrl, appl);
448 application = cmtp_application_get(session, CMTP_APPLID, appl);
449 if (!application) {
450 BT_ERR("Can't find application");
451 return;
454 application->msgnum = cmtp_msgnum_get(session);
456 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
457 CAPI_FUNCTION_RELEASE, NULL, 0);
459 wait_event_interruptible_timeout(session->wait,
460 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
462 cmtp_application_del(session, application);
465 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
467 struct cmtp_session *session = ctrl->driverdata;
468 struct cmtp_application *application;
469 __u16 appl;
470 __u32 contr;
472 BT_DBG("ctrl %p skb %p", ctrl, skb);
474 appl = CAPIMSG_APPID(skb->data);
475 contr = CAPIMSG_CONTROL(skb->data);
477 application = cmtp_application_get(session, CMTP_APPLID, appl);
478 if ((!application) || (application->state != BT_CONNECTED)) {
479 BT_ERR("Can't find application with id %d", appl);
480 return CAPI_ILLAPPNR;
483 CAPIMSG_SETAPPID(skb->data, application->mapping);
485 if ((contr & 0x7f) == session->num) {
486 contr = (contr & 0xffffff80) | 0x01;
487 CAPIMSG_SETCONTROL(skb->data, contr);
490 cmtp_send_capimsg(session, skb);
492 return CAPI_NOERROR;
495 static char *cmtp_procinfo(struct capi_ctr *ctrl)
497 return "CAPI Message Transport Protocol";
500 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
502 struct cmtp_session *session = ctrl->driverdata;
503 struct cmtp_application *app;
504 struct list_head *p, *n;
505 int len = 0;
507 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
508 len += sprintf(page + len, "addr %s\n", session->name);
509 len += sprintf(page + len, "ctrl %d\n", session->num);
511 list_for_each_safe(p, n, &session->applications) {
512 app = list_entry(p, struct cmtp_application, list);
513 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
516 if (off + count >= len)
517 *eof = 1;
519 if (len < off)
520 return 0;
522 *start = page + off;
524 return ((count < len - off) ? count : len - off);
528 int cmtp_attach_device(struct cmtp_session *session)
530 unsigned char buf[4];
531 long ret;
533 BT_DBG("session %p", session);
535 capimsg_setu32(buf, 0, 0);
537 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
538 CAPI_FUNCTION_GET_PROFILE, buf, 4);
540 ret = wait_event_interruptible_timeout(session->wait,
541 session->ncontroller, CMTP_INTEROP_TIMEOUT);
543 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
545 if (!ret)
546 return -ETIMEDOUT;
548 if (!session->ncontroller)
549 return -ENODEV;
551 if (session->ncontroller > 1)
552 BT_INFO("Setting up only CAPI controller 1");
554 session->ctrl.owner = THIS_MODULE;
555 session->ctrl.driverdata = session;
556 strcpy(session->ctrl.name, session->name);
558 session->ctrl.driver_name = "cmtp";
559 session->ctrl.load_firmware = cmtp_load_firmware;
560 session->ctrl.reset_ctr = cmtp_reset_ctr;
561 session->ctrl.register_appl = cmtp_register_appl;
562 session->ctrl.release_appl = cmtp_release_appl;
563 session->ctrl.send_message = cmtp_send_message;
565 session->ctrl.procinfo = cmtp_procinfo;
566 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
568 if (attach_capi_ctr(&session->ctrl) < 0) {
569 BT_ERR("Can't attach new controller");
570 return -EBUSY;
573 session->num = session->ctrl.cnr;
575 BT_DBG("session %p num %d", session, session->num);
577 capimsg_setu32(buf, 0, 1);
579 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
580 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
582 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
583 CAPI_FUNCTION_GET_VERSION, buf, 4);
585 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
586 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
588 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
589 CAPI_FUNCTION_GET_PROFILE, buf, 4);
591 return 0;
594 void cmtp_detach_device(struct cmtp_session *session)
596 BT_DBG("session %p", session);
598 detach_capi_ctr(&session->ctrl);