Commit b4f34d8d authored by David Herrmann's avatar David Herrmann Committed by Gustavo Padovan

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: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo Padovan <gustavo.padovan@collabora.co.uk>
parent 2c8e1411
This diff is collapsed.
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#define __HIDP_H #define __HIDP_H
#include <linux/types.h> #include <linux/types.h>
#include <linux/kref.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/l2cap.h>
/* HIDP header masks */ /* HIDP header masks */
#define HIDP_HEADER_TRANS_MASK 0xf0 #define HIDP_HEADER_TRANS_MASK 0xf0
...@@ -119,42 +121,55 @@ struct hidp_connlist_req { ...@@ -119,42 +121,55 @@ struct hidp_connlist_req {
struct hidp_conninfo __user *ci; struct hidp_conninfo __user *ci;
}; };
int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
int hidp_connection_del(struct hidp_conndel_req *req);
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
int hidp_del_connection(struct hidp_conndel_req *req); int hidp_del_connection(struct hidp_conndel_req *req);
int hidp_get_connlist(struct hidp_connlist_req *req); int hidp_get_connlist(struct hidp_connlist_req *req);
int hidp_get_conninfo(struct hidp_conninfo *ci); int hidp_get_conninfo(struct hidp_conninfo *ci);
enum hidp_session_state {
HIDP_SESSION_IDLING,
HIDP_SESSION_RUNNING,
};
/* HIDP session defines */ /* HIDP session defines */
struct hidp_session { struct hidp_session {
struct list_head list; struct list_head list;
struct kref ref;
struct hci_conn *conn; /* runtime management */
atomic_t state;
wait_queue_head_t state_queue;
atomic_t terminate;
struct task_struct *task;
unsigned long flags;
/* connection management */
bdaddr_t bdaddr;
struct hci_conn *hconn;
struct l2cap_conn *conn;
struct l2cap_user user;
struct socket *ctrl_sock; struct socket *ctrl_sock;
struct socket *intr_sock; struct socket *intr_sock;
struct sk_buff_head ctrl_transmit;
bdaddr_t bdaddr; struct sk_buff_head intr_transmit;
unsigned long flags;
unsigned long idle_to;
uint ctrl_mtu; uint ctrl_mtu;
uint intr_mtu; uint intr_mtu;
unsigned long idle_to;
atomic_t terminate; /* device management */
struct task_struct *task;
unsigned char keys[8];
unsigned char leds;
struct input_dev *input; struct input_dev *input;
struct hid_device *hid; struct hid_device *hid;
struct timer_list timer; struct timer_list timer;
struct sk_buff_head ctrl_transmit; /* Report descriptor */
struct sk_buff_head intr_transmit; __u8 *rd_data;
uint rd_size;
/* session data */
unsigned char keys[8];
unsigned char leds;
/* Used in hidp_get_raw_report() */ /* Used in hidp_get_raw_report() */
int waiting_report_type; /* HIDP_DATA_RTYPE_* */ int waiting_report_type; /* HIDP_DATA_RTYPE_* */
...@@ -166,10 +181,6 @@ struct hidp_session { ...@@ -166,10 +181,6 @@ struct hidp_session {
/* Used in hidp_output_raw_report() */ /* Used in hidp_output_raw_report() */
int output_report_success; /* boolean */ int output_report_success; /* boolean */
/* Report descriptor */
__u8 *rd_data;
uint rd_size;
wait_queue_head_t startup_queue; wait_queue_head_t startup_queue;
int waiting_for_startup; int waiting_for_startup;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment