aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-04-06 14:28:46 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-04-17 02:03:51 -0400
commitb4f34d8d9d26b2428fa7cf7c8f97690a297978e6 (patch)
tree9b513935dfb1b7b83a711462ff4bc9a6f3dbfce0 /net/bluetooth
parent2c8e1411e93391c5a78f55b09697a997474a4707 (diff)
Bluetooth: hidp: add new session-management helpers
This is a rewrite of the HIDP session management. It implements HIDP as an l2cap_user sub-module so we get proper notification when the underlying connection goes away. The helpers are not yet used but only added in this commit. The old session management is still used and will be removed in a following patch. The old session-management was flawed. Hotplugging is horribly broken and we have no way of getting notified when the underlying connection goes down. The whole idea of removing the HID/input sub-devices from within the session itself is broken and suffers from major dead-locks. We never can guarantee that the session can unregister itself as long as we use synchronous shutdowns. This can only work with asynchronous shutdowns. However, in this case we _must_ be able to unregister the session from the outside as otherwise the l2cap_conn object might be unlinked before we are. The new session-management is based on l2cap_user. There is only one way how to add a session and how to delete a session: "probe" and "remove" callbacks from l2cap_user. This guarantees that the session can be registered and unregistered at _any_ time without any synchronous shutdown. On the other hand, much work has been put into proper session-refcounting. We can unregister/unlink the session only if we can guarantee that it will stay alive. But for asynchronous shutdowns we never know when the last user goes away so we must use proper ref-counting. The old ->conn field has been renamed to ->hconn so we can reuse ->conn in the new session management. No other existing HIDP code is modified. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hidp/core.c555
-rw-r--r--net/bluetooth/hidp/hidp.h53
2 files changed, 583 insertions, 25 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index cef1021d5403..8d30a33b27d9 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1,6 +1,7 @@
1/* 1/*
2 HIDP implementation for Linux Bluetooth stack (BlueZ). 2 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org> 3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4 Copyright (C) 2013 David Herrmann <dh.herrmann@gmail.com>
4 5
5 This program is free software; you can redistribute it and/or modify 6 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 it under the terms of the GNU General Public License version 2 as
@@ -20,6 +21,7 @@
20 SOFTWARE IS DISCLAIMED. 21 SOFTWARE IS DISCLAIMED.
21*/ 22*/
22 23
24#include <linux/kref.h>
23#include <linux/module.h> 25#include <linux/module.h>
24#include <linux/file.h> 26#include <linux/file.h>
25#include <linux/kthread.h> 27#include <linux/kthread.h>
@@ -59,6 +61,13 @@ static unsigned char hidp_keycode[256] = {
59 61
60static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; 62static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
61 63
64static int hidp_session_probe(struct l2cap_conn *conn,
65 struct l2cap_user *user);
66static void hidp_session_remove(struct l2cap_conn *conn,
67 struct l2cap_user *user);
68static int hidp_session_thread(void *arg);
69static void hidp_session_terminate(struct hidp_session *s);
70
62static inline void hidp_schedule(struct hidp_session *session) 71static inline void hidp_schedule(struct hidp_session *session)
63{ 72{
64 struct sock *ctrl_sk = session->ctrl_sock->sk; 73 struct sock *ctrl_sk = session->ctrl_sock->sk;
@@ -838,7 +847,7 @@ static int hidp_setup_input(struct hidp_session *session,
838 input->relbit[0] |= BIT_MASK(REL_WHEEL); 847 input->relbit[0] |= BIT_MASK(REL_WHEEL);
839 } 848 }
840 849
841 input->dev.parent = &session->conn->dev; 850 input->dev.parent = &session->hconn->dev;
842 851
843 input->event = hidp_input_event; 852 input->event = hidp_input_event;
844 853
@@ -942,7 +951,7 @@ static int hidp_setup_hid(struct hidp_session *session,
942 snprintf(hid->uniq, sizeof(hid->uniq), "%pMR", 951 snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
943 &bt_sk(session->ctrl_sock->sk)->dst); 952 &bt_sk(session->ctrl_sock->sk)->dst);
944 953
945 hid->dev.parent = &session->conn->dev; 954 hid->dev.parent = &session->hconn->dev;
946 hid->ll_driver = &hidp_hid_driver; 955 hid->ll_driver = &hidp_hid_driver;
947 956
948 hid->hid_get_raw_report = hidp_get_raw_report; 957 hid->hid_get_raw_report = hidp_get_raw_report;
@@ -964,6 +973,543 @@ fault:
964 return err; 973 return err;
965} 974}
966 975
976/* initialize session devices */
977static int hidp_session_dev_init(struct hidp_session *session,
978 struct hidp_connadd_req *req)
979{
980 int ret;
981
982 if (req->rd_size > 0) {
983 ret = hidp_setup_hid(session, req);
984 if (ret && ret != -ENODEV)
985 return ret;
986 }
987
988 if (!session->hid) {
989 ret = hidp_setup_input(session, req);
990 if (ret < 0)
991 return ret;
992 }
993
994 return 0;
995}
996
997/* destroy session devices */
998static void hidp_session_dev_destroy(struct hidp_session *session)
999{
1000 if (session->hid)
1001 put_device(&session->hid->dev);
1002 else if (session->input)
1003 input_put_device(session->input);
1004
1005 kfree(session->rd_data);
1006 session->rd_data = NULL;
1007}
1008
1009/* add HID/input devices to their underlying bus systems */
1010static int hidp_session_dev_add(struct hidp_session *session)
1011{
1012 int ret;
1013
1014 /* Both HID and input systems drop a ref-count when unregistering the
1015 * device but they don't take a ref-count when registering them. Work
1016 * around this by explicitly taking a refcount during registration
1017 * which is dropped automatically by unregistering the devices. */
1018
1019 if (session->hid) {
1020 ret = hid_add_device(session->hid);
1021 if (ret)
1022 return ret;
1023 get_device(&session->hid->dev);
1024 } else if (session->input) {
1025 ret = input_register_device(session->input);
1026 if (ret)
1027 return ret;
1028 input_get_device(session->input);
1029 }
1030
1031 return 0;
1032}
1033
1034/* remove HID/input devices from their bus systems */
1035static void hidp_session_dev_del(struct hidp_session *session)
1036{
1037 if (session->hid)
1038 hid_destroy_device(session->hid);
1039 else if (session->input)
1040 input_unregister_device(session->input);
1041}
1042
1043/*
1044 * Create new session object
1045 * Allocate session object, initialize static fields, copy input data into the
1046 * object and take a reference to all sub-objects.
1047 * This returns 0 on success and puts a pointer to the new session object in
1048 * \out. Otherwise, an error code is returned.
1049 * The new session object has an initial ref-count of 1.
1050 */
1051static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr,
1052 struct socket *ctrl_sock,
1053 struct socket *intr_sock,
1054 struct hidp_connadd_req *req,
1055 struct l2cap_conn *conn)
1056{
1057 struct hidp_session *session;
1058 int ret;
1059 struct bt_sock *ctrl, *intr;
1060
1061 ctrl = bt_sk(ctrl_sock->sk);
1062 intr = bt_sk(intr_sock->sk);
1063
1064 session = kzalloc(sizeof(*session), GFP_KERNEL);
1065 if (!session)
1066 return -ENOMEM;
1067
1068 /* object and runtime management */
1069 kref_init(&session->ref);
1070 atomic_set(&session->state, HIDP_SESSION_IDLING);
1071 init_waitqueue_head(&session->state_queue);
1072 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1073
1074 /* connection management */
1075 bacpy(&session->bdaddr, bdaddr);
1076 session->conn = conn;
1077 session->user.probe = hidp_session_probe;
1078 session->user.remove = hidp_session_remove;
1079 session->ctrl_sock = ctrl_sock;
1080 session->intr_sock = intr_sock;
1081 skb_queue_head_init(&session->ctrl_transmit);
1082 skb_queue_head_init(&session->intr_transmit);
1083 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl)->chan->omtu,
1084 l2cap_pi(ctrl)->chan->imtu);
1085 session->intr_mtu = min_t(uint, l2cap_pi(intr)->chan->omtu,
1086 l2cap_pi(intr)->chan->imtu);
1087 session->idle_to = req->idle_to;
1088
1089 /* device management */
1090 setup_timer(&session->timer, hidp_idle_timeout,
1091 (unsigned long)session);
1092
1093 /* session data */
1094 mutex_init(&session->report_mutex);
1095 init_waitqueue_head(&session->report_queue);
1096
1097 ret = hidp_session_dev_init(session, req);
1098 if (ret)
1099 goto err_free;
1100
1101 l2cap_conn_get(session->conn);
1102 get_file(session->intr_sock->file);
1103 get_file(session->ctrl_sock->file);
1104 *out = session;
1105 return 0;
1106
1107err_free:
1108 kfree(session);
1109 return ret;
1110}
1111
1112/* increase ref-count of the given session by one */
1113static void hidp_session_get(struct hidp_session *session)
1114{
1115 kref_get(&session->ref);
1116}
1117
1118/* release callback */
1119static void session_free(struct kref *ref)
1120{
1121 struct hidp_session *session = container_of(ref, struct hidp_session,
1122 ref);
1123
1124 hidp_session_dev_destroy(session);
1125 skb_queue_purge(&session->ctrl_transmit);
1126 skb_queue_purge(&session->intr_transmit);
1127 fput(session->intr_sock->file);
1128 fput(session->ctrl_sock->file);
1129 l2cap_conn_put(session->conn);
1130 kfree(session);
1131}
1132
1133/* decrease ref-count of the given session by one */
1134static void hidp_session_put(struct hidp_session *session)
1135{
1136 kref_put(&session->ref, session_free);
1137}
1138
1139/*
1140 * Search the list of active sessions for a session with target address
1141 * \bdaddr. You must hold at least a read-lock on \hidp_session_sem. As long as
1142 * you do not release this lock, the session objects cannot vanish and you can
1143 * safely take a reference to the session yourself.
1144 */
1145static struct hidp_session *__hidp_session_find(const bdaddr_t *bdaddr)
1146{
1147 struct hidp_session *session;
1148
1149 list_for_each_entry(session, &hidp_session_list, list) {
1150 if (!bacmp(bdaddr, &session->bdaddr))
1151 return session;
1152 }
1153
1154 return NULL;
1155}
1156
1157/*
1158 * Same as __hidp_session_find() but no locks must be held. This also takes a
1159 * reference of the returned session (if non-NULL) so you must drop this
1160 * reference if you no longer use the object.
1161 */
1162static struct hidp_session *hidp_session_find(const bdaddr_t *bdaddr)
1163{
1164 struct hidp_session *session;
1165
1166 down_read(&hidp_session_sem);
1167
1168 session = __hidp_session_find(bdaddr);
1169 if (session)
1170 hidp_session_get(session);
1171
1172 up_read(&hidp_session_sem);
1173
1174 return session;
1175}
1176
1177/*
1178 * Start session synchronously
1179 * This starts a session thread and waits until initialization
1180 * is done or returns an error if it couldn't be started.
1181 * If this returns 0 the session thread is up and running. You must call
1182 * hipd_session_stop_sync() before deleting any runtime resources.
1183 */
1184static int hidp_session_start_sync(struct hidp_session *session)
1185{
1186 unsigned int vendor, product;
1187
1188 if (session->hid) {
1189 vendor = session->hid->vendor;
1190 product = session->hid->product;
1191 } else if (session->input) {
1192 vendor = session->input->id.vendor;
1193 product = session->input->id.product;
1194 } else {
1195 vendor = 0x0000;
1196 product = 0x0000;
1197 }
1198
1199 session->task = kthread_run(hidp_session_thread, session,
1200 "khidpd_%04x%04x", vendor, product);
1201 if (IS_ERR(session->task))
1202 return PTR_ERR(session->task);
1203
1204 while (atomic_read(&session->state) <= HIDP_SESSION_IDLING)
1205 wait_event(session->state_queue,
1206 atomic_read(&session->state) > HIDP_SESSION_IDLING);
1207
1208 return 0;
1209}
1210
1211/*
1212 * Terminate session thread
1213 * Wake up session thread and notify it to stop. This is asynchronous and
1214 * returns immediately. Call this whenever a runtime error occurs and you want
1215 * the session to stop.
1216 * Note: wake_up_process() performs any necessary memory-barriers for us.
1217 */
1218static void hidp_session_terminate(struct hidp_session *session)
1219{
1220 atomic_inc(&session->terminate);
1221 wake_up_process(session->task);
1222}
1223
1224/*
1225 * Probe HIDP session
1226 * This is called from the l2cap_conn core when our l2cap_user object is bound
1227 * to the hci-connection. We get the session via the \user object and can now
1228 * start the session thread, register the HID/input devices and link it into
1229 * the global session list.
1230 * The global session-list owns its own reference to the session object so you
1231 * can drop your own reference after registering the l2cap_user object.
1232 */
1233static int hidp_session_probe(struct l2cap_conn *conn,
1234 struct l2cap_user *user)
1235{
1236 struct hidp_session *session = container_of(user,
1237 struct hidp_session,
1238 user);
1239 struct hidp_session *s;
1240 int ret;
1241
1242 down_write(&hidp_session_sem);
1243
1244 /* check that no other session for this device exists */
1245 s = __hidp_session_find(&session->bdaddr);
1246 if (s) {
1247 ret = -EEXIST;
1248 goto out_unlock;
1249 }
1250
1251 ret = hidp_session_start_sync(session);
1252 if (ret)
1253 goto out_unlock;
1254
1255 ret = hidp_session_dev_add(session);
1256 if (ret)
1257 goto out_stop;
1258
1259 hidp_session_get(session);
1260 list_add(&session->list, &hidp_session_list);
1261 ret = 0;
1262 goto out_unlock;
1263
1264out_stop:
1265 hidp_session_terminate(session);
1266out_unlock:
1267 up_write(&hidp_session_sem);
1268 return ret;
1269}
1270
1271/*
1272 * Remove HIDP session
1273 * Called from the l2cap_conn core when either we explicitly unregistered
1274 * the l2cap_user object or if the underlying connection is shut down.
1275 * We signal the hidp-session thread to shut down, unregister the HID/input
1276 * devices and unlink the session from the global list.
1277 * This drops the reference to the session that is owned by the global
1278 * session-list.
1279 * Note: We _must_ not synchronosly wait for the session-thread to shut down.
1280 * This is, because the session-thread might be waiting for an HCI lock that is
1281 * held while we are called. Therefore, we only unregister the devices and
1282 * notify the session-thread to terminate. The thread itself owns a reference
1283 * to the session object so it can safely shut down.
1284 */
1285static void hidp_session_remove(struct l2cap_conn *conn,
1286 struct l2cap_user *user)
1287{
1288 struct hidp_session *session = container_of(user,
1289 struct hidp_session,
1290 user);
1291
1292 down_write(&hidp_session_sem);
1293
1294 hidp_session_terminate(session);
1295 hidp_session_dev_del(session);
1296 list_del(&session->list);
1297
1298 up_write(&hidp_session_sem);
1299
1300 hidp_session_put(session);
1301}
1302
1303/*
1304 * Session Worker
1305 * This performs the actual main-loop of the HIDP worker. We first check
1306 * whether the underlying connection is still alive, then parse all pending
1307 * messages and finally send all outstanding messages.
1308 */
1309static void hidp_session_run(struct hidp_session *session)
1310{
1311 struct sock *ctrl_sk = session->ctrl_sock->sk;
1312 struct sock *intr_sk = session->intr_sock->sk;
1313 struct sk_buff *skb;
1314
1315 for (;;) {
1316 /*
1317 * This thread can be woken up two ways:
1318 * - You call hidp_session_terminate() which sets the
1319 * session->terminate flag and wakes this thread up.
1320 * - Via modifying the socket state of ctrl/intr_sock. This
1321 * thread is woken up by ->sk_state_changed().
1322 *
1323 * Note: set_current_state() performs any necessary
1324 * memory-barriers for us.
1325 */
1326 set_current_state(TASK_INTERRUPTIBLE);
1327
1328 if (atomic_read(&session->terminate))
1329 break;
1330
1331 if (ctrl_sk->sk_state != BT_CONNECTED ||
1332 intr_sk->sk_state != BT_CONNECTED)
1333 break;
1334
1335 /* parse incoming intr-skbs */
1336 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
1337 skb_orphan(skb);
1338 if (!skb_linearize(skb))
1339 hidp_recv_intr_frame(session, skb);
1340 else
1341 kfree_skb(skb);
1342 }
1343
1344 /* send pending intr-skbs */
1345 hidp_process_intr_transmit(session);
1346
1347 /* parse incoming ctrl-skbs */
1348 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
1349 skb_orphan(skb);
1350 if (!skb_linearize(skb))
1351 hidp_recv_ctrl_frame(session, skb);
1352 else
1353 kfree_skb(skb);
1354 }
1355
1356 /* send pending ctrl-skbs */
1357 hidp_process_ctrl_transmit(session);
1358
1359 schedule();
1360 }
1361
1362 atomic_inc(&session->terminate);
1363 set_current_state(TASK_RUNNING);
1364}
1365
1366/*
1367 * HIDP session thread
1368 * This thread runs the I/O for a single HIDP session. Startup is synchronous
1369 * which allows us to take references to ourself here instead of doing that in
1370 * the caller.
1371 * When we are ready to run we notify the caller and call hidp_session_run().
1372 */
1373static int hidp_session_thread(void *arg)
1374{
1375 struct hidp_session *session = arg;
1376 wait_queue_t ctrl_wait, intr_wait;
1377
1378 BT_DBG("session %p", session);
1379
1380 /* initialize runtime environment */
1381 hidp_session_get(session);
1382 __module_get(THIS_MODULE);
1383 set_user_nice(current, -15);
1384 hidp_set_timer(session);
1385
1386 init_waitqueue_entry(&ctrl_wait, current);
1387 init_waitqueue_entry(&intr_wait, current);
1388 add_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait);
1389 add_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
1390 /* This memory barrier is paired with wq_has_sleeper(). See
1391 * sock_poll_wait() for more information why this is needed. */
1392 smp_mb();
1393
1394 /* notify synchronous startup that we're ready */
1395 atomic_inc(&session->state);
1396 wake_up(&session->state_queue);
1397
1398 /* run session */
1399 hidp_session_run(session);
1400
1401 /* cleanup runtime environment */
1402 remove_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
1403 remove_wait_queue(sk_sleep(session->intr_sock->sk), &ctrl_wait);
1404 wake_up_interruptible(&session->report_queue);
1405 hidp_del_timer(session);
1406
1407 /*
1408 * If we stopped ourself due to any internal signal, we should try to
1409 * unregister our own session here to avoid having it linger until the
1410 * parent l2cap_conn dies or user-space cleans it up.
1411 * This does not deadlock as we don't do any synchronous shutdown.
1412 * Instead, this call has the same semantics as if user-space tried to
1413 * delete the session.
1414 */
1415 l2cap_unregister_user(session->conn, &session->user);
1416 hidp_session_put(session);
1417
1418 module_put_and_exit(0);
1419 return 0;
1420}
1421
1422static int hidp_verify_sockets(struct socket *ctrl_sock,
1423 struct socket *intr_sock)
1424{
1425 struct bt_sock *ctrl, *intr;
1426 struct hidp_session *session;
1427
1428 if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock))
1429 return -EINVAL;
1430
1431 ctrl = bt_sk(ctrl_sock->sk);
1432 intr = bt_sk(intr_sock->sk);
1433
1434 if (bacmp(&ctrl->src, &intr->src) || bacmp(&ctrl->dst, &intr->dst))
1435 return -ENOTUNIQ;
1436 if (ctrl->sk.sk_state != BT_CONNECTED ||
1437 intr->sk.sk_state != BT_CONNECTED)
1438 return -EBADFD;
1439
1440 /* early session check, we check again during session registration */
1441 session = hidp_session_find(&ctrl->dst);
1442 if (session) {
1443 hidp_session_put(session);
1444 return -EEXIST;
1445 }
1446
1447 return 0;
1448}
1449
1450int hidp_connection_add(struct hidp_connadd_req *req,
1451 struct socket *ctrl_sock,
1452 struct socket *intr_sock)
1453{
1454 struct hidp_session *session;
1455 struct l2cap_conn *conn;
1456 struct l2cap_chan *chan = l2cap_pi(ctrl_sock->sk)->chan;
1457 int ret;
1458
1459 ret = hidp_verify_sockets(ctrl_sock, intr_sock);
1460 if (ret)
1461 return ret;
1462
1463 conn = NULL;
1464 l2cap_chan_lock(chan);
1465 if (chan->conn) {
1466 l2cap_conn_get(chan->conn);
1467 conn = chan->conn;
1468 }
1469 l2cap_chan_unlock(chan);
1470
1471 if (!conn)
1472 return -EBADFD;
1473
1474 ret = hidp_session_new(&session, &bt_sk(ctrl_sock->sk)->dst, ctrl_sock,
1475 intr_sock, req, conn);
1476 if (ret)
1477 goto out_conn;
1478
1479 ret = l2cap_register_user(conn, &session->user);
1480 if (ret)
1481 goto out_session;
1482
1483 ret = 0;
1484
1485out_session:
1486 hidp_session_put(session);
1487out_conn:
1488 l2cap_conn_put(conn);
1489 return ret;
1490}
1491
1492int hidp_connection_del(struct hidp_conndel_req *req)
1493{
1494 struct hidp_session *session;
1495
1496 session = hidp_session_find(&req->bdaddr);
1497 if (!session)
1498 return -ENOENT;
1499
1500 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG))
1501 hidp_send_ctrl_message(session,
1502 HIDP_TRANS_HID_CONTROL |
1503 HIDP_CTRL_VIRTUAL_CABLE_UNPLUG,
1504 NULL, 0);
1505 else
1506 l2cap_unregister_user(session->conn, &session->user);
1507
1508 hidp_session_put(session);
1509
1510 return 0;
1511}
1512
967int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) 1513int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
968{ 1514{
969 struct hidp_session *session, *s; 1515 struct hidp_session *session, *s;
@@ -1006,8 +1552,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
1006 session->ctrl_sock = ctrl_sock; 1552 session->ctrl_sock = ctrl_sock;
1007 session->intr_sock = intr_sock; 1553 session->intr_sock = intr_sock;
1008 1554
1009 session->conn = hidp_get_connection(session); 1555 session->hconn = hidp_get_connection(session);
1010 if (!session->conn) { 1556 if (!session->hconn) {
1011 err = -ENOTCONN; 1557 err = -ENOTCONN;
1012 goto failed; 1558 goto failed;
1013 } 1559 }
@@ -1208,6 +1754,7 @@ module_init(hidp_init);
1208module_exit(hidp_exit); 1754module_exit(hidp_exit);
1209 1755
1210MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 1756MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1757MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
1211MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION); 1758MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1212MODULE_VERSION(VERSION); 1759MODULE_VERSION(VERSION);
1213MODULE_LICENSE("GPL"); 1760MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index c84442061793..c4fb980c2434 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -24,7 +24,9 @@
24#define __HIDP_H 24#define __HIDP_H
25 25
26#include <linux/types.h> 26#include <linux/types.h>
27#include <linux/kref.h>
27#include <net/bluetooth/bluetooth.h> 28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/l2cap.h>
28 30
29/* HIDP header masks */ 31/* HIDP header masks */
30#define HIDP_HEADER_TRANS_MASK 0xf0 32#define HIDP_HEADER_TRANS_MASK 0xf0
@@ -119,42 +121,55 @@ struct hidp_connlist_req {
119 struct hidp_conninfo __user *ci; 121 struct hidp_conninfo __user *ci;
120}; 122};
121 123
124int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
125int hidp_connection_del(struct hidp_conndel_req *req);
122int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); 126int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
123int hidp_del_connection(struct hidp_conndel_req *req); 127int hidp_del_connection(struct hidp_conndel_req *req);
124int hidp_get_connlist(struct hidp_connlist_req *req); 128int hidp_get_connlist(struct hidp_connlist_req *req);
125int hidp_get_conninfo(struct hidp_conninfo *ci); 129int hidp_get_conninfo(struct hidp_conninfo *ci);
126 130
131enum hidp_session_state {
132 HIDP_SESSION_IDLING,
133 HIDP_SESSION_RUNNING,
134};
135
127/* HIDP session defines */ 136/* HIDP session defines */
128struct hidp_session { 137struct hidp_session {
129 struct list_head list; 138 struct list_head list;
139 struct kref ref;
130 140
131 struct hci_conn *conn; 141 /* runtime management */
142 atomic_t state;
143 wait_queue_head_t state_queue;
144 atomic_t terminate;
145 struct task_struct *task;
146 unsigned long flags;
132 147
148 /* connection management */
149 bdaddr_t bdaddr;
150 struct hci_conn *hconn;
151 struct l2cap_conn *conn;
152 struct l2cap_user user;
133 struct socket *ctrl_sock; 153 struct socket *ctrl_sock;
134 struct socket *intr_sock; 154 struct socket *intr_sock;
135 155 struct sk_buff_head ctrl_transmit;
136 bdaddr_t bdaddr; 156 struct sk_buff_head intr_transmit;
137
138 unsigned long flags;
139 unsigned long idle_to;
140
141 uint ctrl_mtu; 157 uint ctrl_mtu;
142 uint intr_mtu; 158 uint intr_mtu;
159 unsigned long idle_to;
143 160
144 atomic_t terminate; 161 /* device management */
145 struct task_struct *task;
146
147 unsigned char keys[8];
148 unsigned char leds;
149
150 struct input_dev *input; 162 struct input_dev *input;
151
152 struct hid_device *hid; 163 struct hid_device *hid;
153
154 struct timer_list timer; 164 struct timer_list timer;
155 165
156 struct sk_buff_head ctrl_transmit; 166 /* Report descriptor */
157 struct sk_buff_head intr_transmit; 167 __u8 *rd_data;
168 uint rd_size;
169
170 /* session data */
171 unsigned char keys[8];
172 unsigned char leds;
158 173
159 /* Used in hidp_get_raw_report() */ 174 /* Used in hidp_get_raw_report() */
160 int waiting_report_type; /* HIDP_DATA_RTYPE_* */ 175 int waiting_report_type; /* HIDP_DATA_RTYPE_* */
@@ -166,10 +181,6 @@ struct hidp_session {
166 /* Used in hidp_output_raw_report() */ 181 /* Used in hidp_output_raw_report() */
167 int output_report_success; /* boolean */ 182 int output_report_success; /* boolean */
168 183
169 /* Report descriptor */
170 __u8 *rd_data;
171 uint rd_size;
172
173 wait_queue_head_t startup_queue; 184 wait_queue_head_t startup_queue;
174 int waiting_for_startup; 185 int waiting_for_startup;
175}; 186};