Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Herrmann and committed by
Gustavo Padovan
b4f34d8d 2c8e1411

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